Models
March 7, 2026 · View on GitHub
Models are simply SQL queries that transform raw data into a structured format suitable for analytics downstream on the Dune app. Think of models as the blueprint for how raw data is transformed into meaningful insights in easy-to-use end tables, i.e., spells.
Naming Standards
Directories
Models live inside sub-project directories. The path depends on whether the spell is sector-level or project-level:
-
Sector-level (in dedicated sub-projects like
dex,nft,tokens):dbt_subprojects/<project>/models/<table_alias>/<blockchain>/platforms/- Example:
dbt_subprojects/dex/models/trades/arbitrum/platforms/
- Example:
-
Sector-level (in
daily_spellbookorhourly_spellbook):dbt_subprojects/<project>/models/_sector/<sector>/<table_alias>/<blockchain>/- Example:
dbt_subprojects/hourly_spellbook/models/_sector/gas/fees/arbitrum/ - Note: The
_sectorprefix is used indaily_spellbookandhourly_spellbookto force sector directories to the top.
- Example:
-
Project-level:
dbt_subprojects/<project>/models/_project/<project_name>/<blockchain>/- Example:
dbt_subprojects/daily_spellbook/models/_project/aave/ethereum/
- Example:
File Names
-
<project_version_blockchain_alias.sql>-
Example:
uniswap_v3_arbitrum_base_trades.sql -
Note: Not all files will contain a version, or a specific blockchain, especially when at cross-chain level.
-
Source & Schema YML Files
Source YML Files
All sources are centralized in the sources/ directory at the root of Spellbook, so they can be reused across sub-projects.
Required for dbt to understand the source schema & table names. Most source files include:
- Schema name of source
- Typically base or decoded tables, but can be anything live on Dune.
- Table name of source
- (optional) Column names
- (optional) Tests / descriptions on columns
Schema YML Files
Every model must have a corresponding entry in a _schema.yml file in the same directory. Schema files are required for dbt to understand the models within the project. Key areas:
- Model name — must match the SQL file name (without
.sql) - Model description — what the model produces and its purpose
- Column descriptions — at minimum for key columns
- Tests — critical for data quality:
dbt_utils.unique_combination_of_columnson the unique key columns (must match the config block'sunique_key)not_nulltests on primary key columns- Seed tests (
check_dex_base_trades_seed,check_seed, etc.) to validate model output against hardcoded expected results
- Model tags — helpful for
dbt lsfilters and project search
Model Materialization
For full config block details, see Model Config Block.
-
View
- Spellbook default if not overwritten in the model config block. Views do not physically store data — the SQL query runs fully on each execution in the Dune app.
- Views are the simplest to build and should be the starting point for each new standalone spell. The main reason to move away from a view is query performance downstream.
-
Incremental
- Best for spells with large, time-series datasets that need frequent updates. Incremental models only process new/changed data each run — the frequency depends on the sub-project (e.g., hourly in
hourly_spellbook, daily indaily_spellbook). - Outside of the config block requirements, the model body requires:
{% if is_incremental() -%}checks (using trailing-only for whitespace control):- Apply on all sources with time-series data (events, transactions, etc.)
- Non-incremental path: Full refresh / initial historical load. Apply a filter for the earliest date of activity for the model
- Incremental path: Apply the
incremental_predicate()macro on the source to match the predicate filter on the target in the config block. Example usage
- Optional use cases:
- Self-referencing the model using the
{{ this }}syntax
- Self-referencing the model using the
- Best for spells with large, time-series datasets that need frequent updates. Incremental models only process new/changed data each run — the frequency depends on the sub-project (e.g., hourly in
-
Table
- Best for spells where data isn't frequently updated at the source, or where a full refresh is simpler than incremental logic. Tables perform a full refresh every run — the frequency depends on the sub-project.
- Like incremental models, tables require
file_format='delta'in the config block. - Common use cases: dimension tables, hardcoded static data, aggregation tables where incremental logic adds unnecessary complexity.