Materialization
Materializations
Materializations define how a model is persisted in your data warehouse. In dex, you can configure each model to be materialized as a table, view, incremental, or ephemeral depending on your use case and performance needs.
By choosing the right materialization strategy, you can optimize speed, cost, storage, and refresh behavior across your data pipeline.
Available Materializations
Table
Creates a physical table in your warehouse. The table is rebuilt each time the model runs, fully replacing its contents.
Best for: Stable datasets that don’t change frequently but need to be queried often.
Pros: Fast queries, predictable behavior
Cons: Full refresh on every run
{{ config(materialized='table') }}View
Creates a logical view—the query is re-executed every time you query the model. No data is stored; only the query definition is saved in your warehouse.
Best for: Lightweight transformations or early development
Pros: Always up-to-date, no storage cost
Cons: Slower performance, depends on upstream availability
{{ config(materialized='view') }}Incremental
Creates or updates a table that only refreshes new or changed records. This is ideal for large datasets where full refreshes would be too costly or slow.
Best for: Fact tables, event logs, large historical data
Pros: Efficient, scalable
Cons: Requires careful logic to avoid duplicates
To use incremental, you must define a unique_key or insert/update logic with filters:
{{ config(materialized='incremental', unique_key='order_id') }}
select *
from staging.orders
{% if is_incremental() %}
where updated_at > (select max(updated_at) from {{ this }})
{% endif %}
Ephemeral
The model is not materialized at all. Instead, its logic is inlined as a CTE (Common Table Expression) in downstream models. It exists only during compilation.
Best for: Lightweight logic reused across models (e.g., deduplication, filters)
Pros: No warehouse object created, fast compile
Cons: Can be hard to debug, only usable as part of other models
{{ config(materialized='ephemeral') }}Setting Default Materializations
You can set materializations:
1. At the model level
Use the config() block at the top of your .sql file:
{{ config(materialized='table') }}
select * from {{ ref('customers') }}
2. At the folder level in dbt_project.yml
dbt_project.ymlThis defines defaults for every model in a folder:
models:
my_project:
1.raw:
+materialized: view
2.cleaned:
+materialized: table
3.trusted:
+materialized: incremental
You can override this per model using config(). Read more about configuring defaults here.
Best Practices
Use
viewfor early-stage dev and quick iterationUse
tablefor finalized models with frequent reuseUse
incrementalfor high-volume, slowly changing datasetsUse
ephemeralfor modular, reusable logic
Last updated
Was this helpful?

