| name | snowflake |
| description | Snowflake playbook. Workflows for RBAC rollout, warehouse sizing and cost control, secure data sharing, Streams/Tasks/Snowpipe pipelines, permissions audit, and Time Travel / Fail-safe recovery. Use when designing, operating, or auditing Snowflake. |
Snowflake - Playbook
Companion rule: 482-snowflake.mdc. This skill turns those patterns into end-to-end workflows.
When to invoke
Use when the user is:
- Designing a new Snowflake account, database, or warehouse
- Rolling out or auditing RBAC (roles, grants, object ownership)
- Tuning cost (warehouse sizing, auto-suspend, query optimization, storage)
- Building pipelines with Snowpipe, Streams, Tasks, or Dynamic Tables
- Setting up secure data sharing (Reader Accounts, Snowflake Marketplace, Private Listings)
- Recovering from a bad change (Time Travel, Fail-safe)
- Governing sensitive data (masking, row access policies, tagging)
Golden Rules
- Roles hold privileges; users hold roles. Never grant directly to users.
- Use
USE ROLE at the top of every script. Implicit roles cause access-denied mysteries.
- Warehouses suspend aggressively (60s auto-suspend for interactive; higher for streaming).
- Right-size warehouses; scale with multi-cluster, not with XL.
- Time Travel is real; Fail-safe is last-resort. Set retention deliberately per schema.
- Every production role chain has an owner and an audit trail.
Workflow 1 - RBAC Rollout
Design a production-grade role hierarchy and migrate away from ACCOUNTADMIN-as-default.
Steps
- Map your access model to Snowflake's RBAC:
- System roles:
ORGADMIN, ACCOUNTADMIN, SECURITYADMIN, USERADMIN, SYSADMIN, PUBLIC
- Custom roles: business- and data-oriented
- Use the standard hierarchy:
- Functional roles (granted to users): e.g.,
ANALYST_SALES, ENGINEER_DATA, ADMIN_FINOPS
- Access roles (hold privileges on objects): e.g.,
DB_SALES_READ, DB_SALES_WRITE, WH_LOAD_USE
- Functional roles inherit from access roles, not from each other
- Ownership:
- Custom databases / schemas / warehouses are OWNED by a custom role (e.g.,
DB_SALES_OWNER), never by ACCOUNTADMIN
SYSADMIN sits above functional roles; custom-role-owned objects grant managed access through their owner role
- USE MANAGED ACCESS schemas for any schema where multiple teams grant access - centralize grant control.
- Separation of duties:
USERADMIN manages users + role grants; SECURITYADMIN manages privilege grants on objects; they do NOT overlap
- Application service users are locked to a specific role via
DEFAULT_ROLE and cannot switch
- Audit:
- Snapshot
GRANTS to a governance schema nightly (SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_ROLES)
- Alert on new grants to
ACCOUNTADMIN / SECURITYADMIN
- Terraform / dbt:
- Manage roles and grants via
snowflake-terraform-provider (Snowflake Labs) or Permifrost (dbt Labs)
- PR-reviewed changes; drift detection
- Migrate existing access incrementally; lock down
ACCOUNTADMIN-for-daily-use.
Deliverable: Role hierarchy diagram, Terraform modules, audit job, migration runbook.
See references/rbac-patterns.md.
Workflow 2 - Warehouse Sizing and Cost Control
Keep Snowflake cheap without starving workloads.
Steps
- Classify workloads:
- Interactive (BI, ad-hoc) - small/medium WH, multi-cluster auto-scale, short auto-suspend
- Batch ETL - medium/large WH, single cluster, on-demand
- Streaming (Snowpipe, Tasks) - small WH, tasks share warehouses
- ML / heavy - large/xlarge WH, purpose-specific
- Start small, scale on evidence. Double warehouse size only if >50% of query time is spillage or queueing.
- Multi-cluster warehouses for concurrency, not for speed. A bigger warehouse makes one query faster; multi-cluster lets more concurrent queries run at the same speed.
- Auto-suspend:
- Interactive: 60s
- Batch / streaming: 60-600s depending on duty cycle
- Never
AUTO_SUSPEND = 0 in prod
- Resource monitors per warehouse (or per warehouse group):
- Daily, weekly, monthly credit quotas
- Actions: notify at 75%, suspend at 100%
- Owner and escalation path in the notification message
- Query tuning:
EXPLAIN and QUERY_HISTORY the slow queries
- Prune with clustering keys only when necessary (micro-partition pruning is automatic - test before adding)
- Materialize results (tables / materialized views) for repeated heavy scans
- Use Query Acceleration Service for BI workloads with unpredictable heavy queries
- Storage:
- Time Travel retention appropriate to schema (0 for staging scratch, 1d for most, 7-90d for critical)
- Transient / temporary tables for scratch
- Track storage cost by database with ACCOUNT_USAGE.STORAGE_DAILY_HISTORY
- Reports:
- Weekly top-N queries by credit cost
- Weekly top-N tables by storage growth
- Month-over-month trend
Deliverable: Warehouse catalog, resource monitors, dashboard, slow-query hit list.
Workflow 3 - Pipeline via Snowpipe / Streams / Tasks / Dynamic Tables
When to use which
| Use | Why |
|---|
| Snowpipe | Continuous ingestion from S3/GCS/ADLS into raw tables |
| Streams | CDC (change-tracking) on tables; power incremental pipelines |
| Tasks | Scheduled or conditional SQL; often reads from streams |
| Dynamic Tables | Declarative, managed materialization (prefer over manual Stream+Task where it fits) |
| Snowflake Connector for Kafka | Direct Kafka ingestion when latency < Snowpipe is needed |
Design pattern
Cloud storage --Snowpipe--> raw.tableRaw (VARIANT)
|
| Stream cdc_raw
v
staging.tableStaged <--Task-- INSERT/MERGE from raw via stream consumption
|
| Stream cdc_staging
v
warehouse.fact_table <--Task-- MERGE into dimensional model
Or with Dynamic Tables:
raw.tableRaw --> dt_staging (target lag 5 min) --> dt_fact (target lag 15 min)
Guardrails
- Idempotent MERGE (use stable business keys)
- DLQ table for malformed rows
- Monitoring: unprocessed stream rows, task failure count, ingestion latency
- Alert thresholds and runbook for each pipeline
Workflow 4 - Secure Data Sharing
Share data without moving it.
Options
- Listings (Snowflake Marketplace): public or private catalog-based sharing
- Private Listings: curated access with request workflow
- Direct Shares: account-to-account inside the same cloud region; cross-region uses Replication
- Reader Accounts: consumer gets a Snowflake account you pay for (to share with non-Snowflake customers)
Design checklist
- Secure views / secure UDFs for shared objects (prevent data peek via
EXPLAIN)
- Explicit column selection; no
SELECT * on shared views
- Row access policies for tenant-level filtering where applicable
- Masking policies for any PII in shared objects
- Document retention / SLA for the share; versioning strategy for schema changes
- Consumer-side usage reported back via
SHARE_USAGE (governance)
Workflow 5 - Permissions Audit
Quarterly or after any org change.
Steps
- Dump grants from
SNOWFLAKE.ACCOUNT_USAGE.GRANTS_TO_USERS, GRANTS_TO_ROLES, GRANTS_ON_OBJECTS.
- Flag:
- Direct grants to users (should be zero)
ACCOUNTADMIN / SECURITYADMIN granted to non-service identities beyond a small list
- Privileges granted to
PUBLIC
- Objects owned by
ACCOUNTADMIN (drift; should be owned by custom role)
- Check users:
- Disabled / stale users still holding roles
- Service users without scoped roles
- Check network policies:
- Service users restricted to known CIDRs / PrivateLink
- Admin roles require MFA
- Masking / row-access policies:
- Cover all PII columns?
- Applied via tags where feasible
- File findings with owner, severity, fix.
Workflow 6 - Recovery via Time Travel and Fail-safe
Time Travel = queryable historical data (0-90 days, per-object DATA_RETENTION_TIME_IN_DAYS).
Fail-safe = Snowflake-only recovery, 7 days, for permanent tables only, not self-serve.
Recovery playbook
-
Quantify the blast radius: which objects, what time, which rows?
-
Query the past with AT(OFFSET => ...), AT(TIMESTAMP => ...), BEFORE(STATEMENT => ...):
SELECT * FROM my_table AT(OFFSET => -3600);
SELECT * FROM my_table BEFORE(STATEMENT => '<query_id>');
-
Clone to isolate:
CREATE TABLE my_table_recovered CLONE my_table AT(OFFSET => -3600);
-
Restore selectively (SQL MERGE from clone).
-
Undrop recently-dropped objects:
UNDROP TABLE my_table;
-
If Time Travel is expired, engage Snowflake support for Fail-safe recovery. Not self-serve; not a plan.
Prevention
- Set
DATA_RETENTION_TIME_IN_DAYS per schema (>= 7 for prod, >= 30 for critical)
TRANSIENT tables where durability matters less than cost
- Don't
DROP DATABASE in prod from a human session; use roles that cannot
Anti-patterns
- Users with
ACCOUNTADMIN for daily work
- Grants direct to users
AUTO_SUSPEND disabled or very long on interactive warehouses
- Clustering keys added "for performance" without an
EXPLAIN showing benefit
SELECT * across wide VARIANT tables in production queries
- Secrets in SQL scripts or task definitions (use External Functions + vault)
- Tasks using
ACCOUNTADMIN as OWNER
- Shares exposing base tables instead of secure views
- No resource monitors on shared warehouses
- No storage / credit dashboard
References
Related
- Rule:
482-snowflake.mdc
- Rule:
480-data-engineering.mdc (cross-platform data contracts, DQ, governance)
- Rule:
475-sql.mdc (safe SQL patterns)
- Rule:
316-zero-trust.mdc (data tier controls)
- Skill:
data-engineering (pipeline concepts)
- Skill:
database-postgresql (for comparison)