모델, 소스, Ref 참조
모델(Model): 변환 로직의 단위
dbt에서 모델은 단 하나의 SELECT 문으로 이루어진 .sql 파일이다. 파일 이름이 곧 웨어하우스에 생성될 테이블·뷰의 이름이 된다. INSERT, UPDATE, DELETE, CREATE 같은 DDL·DML은 모델 파일에 작성하지 않는다. dbt가 Materialization 설정을 보고 적절한 DDL을 자동으로 생성한다.
-- models/staging/stg_orders.sql
select
id as order_id,
user_id,
status,
created_at
from {{ source('shop', 'orders') }}이 파일 하나가 웨어하우스에서 stg_orders라는 뷰(기본 Materialization)로 만들어진다. 변환 로직이 파일 단위로 분리되므로 재사용·테스트·문서화가 모두 파일 수준에서 가능해진다.
소스(Sources)와 source() 함수
소스는 dbt가 직접 만든 것이 아닌, 외부에서 이미 웨어하우스에 적재된 원본 테이블을 가리킨다. Fivetran이나 Airbyte가 올린 원시 데이터가 대표적이다.
소스는 sources.yml(또는 schema.yml)에 선언한다:
# models/staging/sources.yml
version: 2
sources:
- name: shop
database: production
schema: raw
tables:
- name: orders
description: "Shopify 주문 원본 테이블"
- name: customers모델 파일 안에서는 {{ source('소스명', '테이블명') }}으로 참조한다. 단순한 문자열 대체처럼 보이지만, 두 가지 중요한 역할을 한다.
- DAG 경계 선언: dbt는
source()호출을 인식해 DAG의 시작 노드로 등록한다.dbt docs generate를 실행하면 소스에서 최종 mart까지 전체 계보(lineage)가 자동으로 시각화된다. source freshness테스트:loaded_at_field를 지정하면dbt source freshness명령으로 소스 테이블이 얼마나 오래됐는지 검사할 수 있다. 파이프라인 지연 감지에 쓰인다.
ref() 함수: 모델 간 의존 선언
ref() 함수는 dbt에서 가장 중요한 Jinja 함수다. 한 모델이 다른 모델을 참조할 때 사용하며, 의존 관계를 선언하는 유일한 공식 방법이다.
-- models/marts/fct_orders.sql
select
o.order_id,
o.status,
c.customer_name,
o.created_at
from {{ ref('stg_orders') }} as o
join {{ ref('stg_customers') }} as c
on o.user_id = c.customer_idref('stg_orders')는 컴파일 시점에 analytics.stg_orders 같은 실제 스키마·테이블명으로 치환된다. 직접 테이블명을 하드코딩하면 환경(dev/staging/prod)이 달라질 때 SQL을 수정해야 하지만, ref()를 쓰면 profiles.yml의 schema 설정만 바꾸면 자동으로 대응된다.
또한 dbt는 모든 ref() 호출을 추적해 DAG의 간선(edge)으로 등록한다. 순환 참조(A → B → A)가 생기면 즉시 컴파일 오류로 알려준다.
레이어 구조: staging → intermediate → marts
dbt 공식 가이드에서 권장하는 폴더 구조는 세 계층이다.
Staging 레이어는 소스 테이블과 1:1로 대응하며, 컬럼명 정제·타입 캐스팅·기본 필터만 처리한다. source() 호출은 staging 레이어에서만 허용하는 것이 관례다. 뷰(view)로 Materialization하는 것이 일반적이다.
Intermediate 레이어는 staging 모델들을 조합해 복잡한 비즈니스 로직을 표현한다. BI 도구가 직접 접근하지 않으므로 ephemeral(CTE 인라인)로 두거나 뷰로 두는 경우가 많다.
Marts 레이어는 비즈니스 영역(marketing, finance, product)별로 구분된 최종 테이블이다. BI 도구가 직접 쿼리하는 대상이므로 테이블(table)로 Materialization해 조회 성능을 확보한다. fct_(팩트 테이블), dim_(디멘션 테이블) 접두사로 데이터 웨어하우스 모델링 관례를 따른다.
YAML 메타데이터: 스키마와 문서
각 계층 디렉터리에는 YAML 파일을 두어 모델을 문서화하고 테스트를 선언한다:
# models/staging/schema.yml
version: 2
models:
- name: stg_orders
description: "주문 원본을 정제한 staging 모델"
columns:
- name: order_id
description: "주문 고유 ID"
tests:
- not_null
- unique
- name: status
tests:
- accepted_values:
values: ['placed', 'shipped', 'returned']dbt test 명령을 실행하면 선언된 테스트가 웨어하우스 쿼리로 변환되어 실행된다. 테스트는 별도 챕터에서 자세히 다룬다.
한 줄 정리
dbt 모델은 SELECT 문 하나로 정의되며, source()로 외부 원본을, ref()로 모델 간 의존을 선언해 DAG를 자동 구성한다. staging → intermediate → marts 레이어 구조가 복잡한 변환 로직을 관리 가능한 단위로 분리하는 핵심이다.
References
- https://docs.getdbt.com/best-practices/how-we-structure/2-staging
- https://docs.getdbt.com/best-practices/how-we-structure/4-marts
- https://docs.getdbt.com/reference/dbt-jinja-functions/ref
- https://medium.com/@alegeahmadolaitan/modern-data-transformation-with-dbt-a-guide-for-analysts-and-engineers-47d0fb007201
- https://popsql.com/blog/dbt-models
- https://oneuptime.com/blog/post/2026-01-27-dbt-models-effective/view
- https://blog.pmunhoz.com/blog/dbt/dbt-core-source-vs-models/