footer_logo
A practical guide for building governed, testable analytics  with dbt on Snowflake

A practical guide for building governed, testable analytics with dbt on Snowflake

Hanumanthrao S

By Hanumanthrao S • 3/16/2026

Moving from ETL to ELT lets you land raw data in Snowflake first and transform it in the warehouse using dbt.


Blog Description Image

Figure 1. ETL vs ELT — modern data movement

Moving from ETL to ELT lets you land raw data in Snowflake first and transform it in the warehouse using dbt. You get simpler pipelines, version-controlled SQL, automated testing, and faster iteration—without the fragility of heavyweight transform servers.

Why ELT (and why now)?

Traditional ETL pushed heavy transforms into middleware before loading to the warehouse—expensive servers, complex dependencies, and hard-to-version logic. ELT flips it: Extract and Load data directly into Snowflake, then Transform it in-warehouse with dbt.

Benefits:

  • Elastic compute in Snowflake for scalable transforms.

  • SQL-as-code with dbt: modular models, tests, docs, lineage, and CI.

  • Faster iteration and simpler orchestration.

The dbt + Snowflake mental model

Use clear layers to separate concerns and speed iteration:

Blog Description Image

Figure 2. dbt layers inside Snowflake—Raw → Staging → Core → Marts

Raw layer

Land source tables 1:1 (e.g., raw.stripe_charges, raw.shopify_orders). Keep them immutable; add snapshots if you need historical tracking.

Staging layer

Clean types, standardize timestamps/IDs, and apply light semantics (one model per source table).

Core layer (marts)

Build business entities and facts: dim_customer, fct_orders, fct_revenue. Aggregate, join, and enforce grain here.

Serving layer

Thin, consumption-friendly models for BI tools (Tableau/Power BI/Looker) or data apps.

A concrete mini-architecture

/dbt_project

/models

/sources

stripe.yml

shopify.yml

/staging

stg_stripe__charges.sql

stg_shopify__orders.sql

/core

dim_customer.sql

fct_orders.sql

fct_revenue.sql

/marts

finance__daily_rev.sql

marketing__customer_cohort.sql

/snapshots

customers_snapshot.sql

/tests

schema.yml

/macros

get_loaded_at.sql

safe_divide.sql

Example source config (models/sources/stripe.yml)

version: 2

sources:

- name: stripe

schema: raw

tables:

- name: charges

loaded_at_field: _loaded_at

freshness:

warn_after: {count: 6, period: hour}

error_after: {count: 24, period: hour}

Example staging model (models/staging/stg_stripe__charges.sql)

with src as (

select

id as charge_id,

customer as customer_id,

amount/100.0 as amount_usd,

status,

created as created_ts

from {{ source('stripe', 'charges') }}

)

select * from src

Example fact model (models/core/fct_revenue.sql)

{{ config(materialized='incremental', unique_key='charge_id') }}

with charges as (

select * from {{ ref('stg_stripe__charges') }}

)

select

charge_id,

customer_id,

amount_usd,

status,

date_trunc('day', created_ts) as charge_date

from charges

{% if is_incremental() %}

where created_ts > (select coalesce(max(charge_date), '1900-01-01')

from {{ this }})

{% endif %}

Validation tests (models/tests/schema.yml)

version: 2

models:

- name: fct_revenue

tests:

- not_null:

column_name: charge_id

- unique:

column_name: charge_id

Cost & performance in Snowflake

Blog Description Image

Figure 3. Right-size warehouses per workload; pay only for what you use.

  • Use dedicated Small/Medium/Large warehouses for Dev, scheduled transforms, and backfills.

  • Prefer incremental models for large facts; choose a robust unique_key.

  • Consider clustering on high-selectivity columns and leverage result caching.

  • Separate dev/prod using roles, databases, and warehouses; map them to dbt targets.

Orchestration & CI/CD with dbt

Blog Description Image

Figure 4. CI/CD pipeline for dbt—PR → Build → Test → Deploy

Options: dbt Cloud for jobs and artifacts; or Airflow/Prefect/GitHub Actions with commands like:

dbt depsdbt seeddbt rundbt test

Data governance & quality built in

  • Source freshness checks ensure upstream loads are timely.

  • Schema and custom tests prevent regressions (e.g., amount_usd >= 0).

  • Snapshots track SCD changes over time.

  • dbt docs provides searchable lineage and model descriptions.

Migrating from ETL to ELT (a phased plan)

Blog Description Image

Figure 5. Phased migration from ETL to ELT

  1. Parallel run: keep legacy ETL, start landing the same sources to raw.* in Snowflake.

  2. Recreate transforms in dbt model-by-model, starting with high-leverage facts/dims.

  3. Validate row counts, checksums, and KPI parity.

  4. Cutover BI to dbt marts then retire equivalent ETL transforms.

  5. Harden: add tests, freshness, snapshots; wire CI/CD.

  6. Optimize: incrementalization, warehouse sizing, cluster keys, and caching.

Example: daily finance revenue mart

Goal: product analytics & finance both need consistent daily revenue. Use fct_revenue for atomic transactions and a finance_daily_rev model for daily aggregates by currency/customer/region.

Recommended tests: no duplicate day+customer and non-negative amounts. BI should query the daily mart directly.

Common pitfalls (and how to avoid them)

  • Re-creating monolithic ETL: keep transforms modular with clear ref() boundaries.

  • Giant do-everything models: split into staging → core → marts.

  • No tests: start with unique/not_null + a few business rules.

  • Skipping incrementalization on large facts.

  • Mixing dev & prod environments.

Final checklist

  • Raw sources defined with freshness in sources/*.yml

  • Staging models per table with type/semantic cleanup

  • Core facts/dims with clear grain & unique_key

  • Incremental configs for big facts

  • Tests (schema + business) and source freshness

  • Environments mapped to dbt targets and Snowflake roles/warehouses

  • CI running dbt build on PRs

  • Docs generated and shared with stakeholders

Call to action

If you’re still pushing heavy transformations through external ETL tools, this is the moment to modernize. Start with a single domain, define raw sources, build clean staging models, add tests, and let Snowflake + dbt handle the transformation layer. Your pipelines will be simpler, faster, and far easier to trust.

Loading comments...

footer_logo
At YBrantWorks we are passionate about providing businesses with the IT solutions they need to succeed in today's competitive marketplace.

Follow us

Services

Tailor-made Software Development

Data Analytics

AI & ML Solutions

Web Development

Cloud Consulting

Staff Augmentation

Contact Us

  G 602, Tower 3 Daffodils, Adarsh Palm Retreat, Devarabeesanahalli, Bangalore KA 560103

  info@ybrantworks.com
  +91 9663422557