Snowflake is a cloud data platform that separates storage from compute. Your data lives once in cloud storage, and you spin up independent compute clusters, called virtual warehouses, to query it. That one idea explains most of what makes Snowflake pleasant to work with: teams do not slow each other down, and you only pay for compute while it is running.
The object hierarchy
Everything in Snowflake sits inside a simple hierarchy: an account contains databases, which contain schemas, which contain tables, views, stages and other objects. A common layout for analytics is one database per environment and one schema per layer.
CREATE DATABASE IF NOT EXISTS analytics;
CREATE SCHEMA IF NOT EXISTS analytics.raw; -- data as it arrives
CREATE SCHEMA IF NOT EXISTS analytics.staging; -- cleaned and renamed
CREATE SCHEMA IF NOT EXISTS analytics.marts; -- facts and dimensions for reporting
USE DATABASE analytics;
USE SCHEMA raw;Virtual warehouses: compute you switch on and off
A warehouse is a cluster of compute resources. Size determines speed and cost; each size up roughly doubles both. For most small and medium workloads, an extra-small warehouse with a short auto-suspend is plenty.
Standard warehouses. You are billed per second while the warehouse runs, with a 60-second minimum each time it starts; newer warehouse types are priced differently.
CREATE WAREHOUSE IF NOT EXISTS transform_wh
WAREHOUSE_SIZE = 'XSMALL'
AUTO_SUSPEND = 60 -- seconds of inactivity before pausing
AUTO_RESUME = TRUE
INITIALLY_SUSPENDED = TRUE;
USE WAREHOUSE transform_wh;Loading data: stages and COPY INTO
A stage is a location where files wait to be loaded. It can be internal (managed by Snowflake) or external (your own S3, Azure or Google Cloud bucket). COPY INTO then loads the files into a table, and remembers which files it has already loaded.
CREATE OR REPLACE FILE FORMAT csv_format
TYPE = CSV
SKIP_HEADER = 1
FIELD_OPTIONALLY_ENCLOSED_BY = '"'
NULL_IF = ('', 'NULL');
CREATE OR REPLACE STAGE raw_stage FILE_FORMAT = csv_format;
-- From SnowSQL or the Snowflake CLI, upload a local file:
-- PUT file://orders_2026_09.csv @raw_stage;
CREATE OR REPLACE TABLE raw.orders (
order_id NUMBER,
customer_id NUMBER,
order_date DATE,
amount NUMBER(10, 2)
);
COPY INTO raw.orders
FROM @raw_stage
PATTERN = '.*orders_.*[.]csv'
ON_ERROR = 'ABORT_STATEMENT';Semi-structured data with VARIANT
Snowflake stores JSON natively in a VARIANT column and lets you query it with a path syntax. FLATTEN turns arrays into rows.
CREATE OR REPLACE TABLE raw.events (payload VARIANT);
SELECT
payload:order_id::NUMBER AS order_id,
payload:customer.email::STRING AS email,
item.value:sku::STRING AS sku,
item.value:qty::NUMBER AS qty
FROM raw.events,
LATERAL FLATTEN(input => payload:items) AS item;Time travel and UNDROP
Snowflake keeps historical versions of your data for a retention period (one day by default, configurable up to 90 days on Enterprise edition). You can query the past, or restore dropped objects.
-- The table as it was 30 minutes ago
SELECT * FROM marts.fct_sales AT(OFFSET => -60 * 30);
-- Recover from an accidental delete by re-inserting yesterday's rows
INSERT INTO marts.fct_sales
SELECT * FROM marts.fct_sales AT(TIMESTAMP => DATEADD(day, -1, CURRENT_TIMESTAMP()))
WHERE order_date = '2026-09-29';
-- Bring back a dropped table
UNDROP TABLE marts.fct_sales;Zero-copy cloning
Cloning creates a full, writable copy of a table, schema or database instantly, without duplicating storage. Changes are only stored when either copy is modified. It is perfect for development environments and safe testing.
CREATE DATABASE analytics_dev CLONE analytics;
CREATE TABLE marts.fct_sales_backup CLONE marts.fct_sales;Automating with streams and tasks
A stream tracks changes to a table; a task runs SQL on a schedule. Together they give you simple incremental pipelines without an external scheduler.
CREATE OR REPLACE STREAM raw.orders_stream ON TABLE raw.orders;
CREATE OR REPLACE TASK load_orders
WAREHOUSE = transform_wh
SCHEDULE = 'USING CRON 0 6 * * * Europe/London'
WHEN SYSTEM$STREAM_HAS_DATA('raw.orders_stream')
AS
INSERT INTO staging.orders
SELECT order_id, customer_id, order_date, amount
FROM raw.orders_stream
WHERE METADATA$ACTION = 'INSERT';
ALTER TASK load_orders RESUME; -- tasks are created suspendedKeeping costs under control
- 1
Start small
Every warehouse at
XSMALLwithAUTO_SUSPEND = 60; only size up when a real workload needs it. - 2
Set a resource monitor
A monthly credit quota with alerts.
- 3
Avoid SELECT * on wide tables
Snowflake stores data by column, so reading fewer columns scans less data.
- 4
Review the expensive queries
Check
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORYeach month.
Check your understanding
1/3What happens to a warehouse with AUTO_SUSPEND = 60 after a minute of inactivity?
AUTO_RESUME then restarts it when the next query arrives.
2/3How do you create a full, writable copy of a database without duplicating storage?
Changes are only stored when either copy is modified.
3/3Which pair gives you incremental pipelines inside Snowflake?
A stream tracks changes; a task runs SQL on a schedule.
You got 0 out of 3.
Snowflake now also runs AI agents on your data: see Snowflake vs Databricks for AI agents and Apache Iceberg v3 for open tables. For the latest features, read the Snowflake October 2026 update.
Once you are comfortable here, the natural next step is managing these transformations as code with dbt. The Snowflake cheat sheet keeps all of these commands on one page.
