Structure
Project layout, sling_build.yml configuration, naming, dev & prod mode, and model selectors.
A Sling Build project is a directory with SQL model files, optional seed files, and an optional sling_build.yml configuration. The first folder is the schema. The file name is the table name.
Project Layout
By default, Sling uses a flat structure. Models and seeds are together in the same directories:
my_project/
├── sling_build.yml # project config (optional)
├── utils.macros.sql # global macros
├── raw.sql # model → public.raw
├── staging/
│ ├── stg_orders.sql # model → staging.stg_orders
│ ├── stg_customers.sql # model → staging.stg_customers
│ ├── country_codes.csv # seed → staging.country_codes
│ └── helpers.macros.sql # scoped macros (staging only)
├── marts/
│ └── core/
│ ├── dim_customers.sql # model → marts.dim_customers
│ └── fct_orders.sql # model → marts.fct_orders
└── seeds/
└── status_map.json # seed → seeds.status_mapNaming Rules
The folder structure sets the schema. The file name sets the table name:
1st folder level = schema name
File name = model name and table name
Nested folders = organization only. They do not change the table name
Root-level files =
publicschema (default)
raw.sql
public
raw
public.raw
staging/stg_orders.sql
staging
stg_orders
staging.stg_orders
staging/country_codes.csv
staging
country_codes
staging.country_codes
marts/core/dim_customers.sql
marts
dim_customers
marts.dim_customers
marts/core/fct_orders.sql
marts
fct_orders
marts.fct_orders
analytics/plausible/events.sql
analytics
events
analytics.events
seeds/status_map.json
seeds
status_map
seeds.status_map
The model name is the file name without the extension. It does not change in dev mode. ref(), selectors, and @name accept the model name or the prod table name (analytics.events).
File Classification
.sql
Model
Compiled and executed against target
.macros.sql
Macro file
Gives reusable Jinja macros, not executed as a model
.csv
Seed
Loaded into target with Sling task infrastructure
.json
Seed
Loaded into target with Sling task infrastructure
.parquet
Seed
Loaded into target with Sling task infrastructure
Other
Ignored
Files with other extensions are skipped
sling_build.yml
The project configuration file sets the target connection, dev mode settings, variables, and defaults.
Top-Level Keys
target
string
Target database connection name (required)
dev
object
Dev mode settings. Presence activates dev mode by default
dev.target
string
(top-level target)
Optional separate connection for dev mode
dev.schema
string
Schema for dev mode (required when dev is present)
dev.database
string
(defaults.database)
Database for dev mode. Three-part dialects only
dbt_project
bool/object
false
Enable dbt-compatible directory structure
vars
map
{}
Variables available in Jinja templates
defaults
object
Default model settings. See below
defaults Keys
These apply to every model. Model front-matter overrides them.
mode
string
full-refresh
Default materialization mode
schema
string
Default schema override
database
string
Default database override. Three-part dialects only
tags
list
[]
Tags applied to all models. Additive with model tags
unique_key
string or list
Default merge key(s)
update_key
string
Default incremental watermark column
merge_strategy
string
delete+insert
Default merge strategy
enabled
bool
true
Set false to disable models by default
hooks
object
Default start/end hooks. Additive with model hooks, parent first
drop_cascade
bool
false
Add CASCADE to DROP statements
Database (Three-Part Names)
Some dialects address an object as database.schema.table. Set the database key to use the three-part form. Folders never set the database.
A model can override the database in its front-matter:
Resolution order for database:
Model front-matter
database:.dev.databasein dev mode.defaults.databasefrom the effective config.Empty. The name stays two-part.
Supported dialects: Snowflake, BigQuery, Databricks, Trino, DuckDB (and DuckLake, MotherDuck), SQL Server, Azure SQL, Azure Synapse, and Fabric.
Other dialects fail at compile time:
Create sling_build.yml
Write sling_build.yml in the model folder and set target: to a connection name. For a full Sling project, run sling init. That command writes models/sling_build.yml.
You can also pass --target on sling build run and use no file.
DBT-Compatible Structure
Set dbt_project: true to use separate models/ and seeds/ directories:
For custom paths:
Dev & Prod Mode
Dev and prod modes isolate development work from production data. Dev mode sends all models into a single schema. Prod mode uses the folder-based schema mapping.
Prod (default)
Folder-based schemas (1st folder = schema)
No dev block in yml, or --prod flag
Dev
All models in a single dev schema, same table names
dev block present in yml, or --schema flag
Configuring Dev Mode
Add a dev block to your sling_build.yml. When present, dev mode is active by default.
dev.schemais mandatory whendevis presentdev.targetis optional. If you do not set it, Sling uses the top-leveltarget
Variables in sling_build.yml
sling_build.yml expands ${VAR} and ${VAR:-fallback} before parse. Bare $VAR is not expanded. One committed file can name a per-user dev schema:
On macOS and Linux the OS already sets USER to the login name, so env.yaml does not override it. Export a different value in the shell, or use a Sling-specific name such as ${SLING_DEV_USER}.
An unset variable with no fallback is an error only when the field is in effect:
dev.schema: dev_${USER}, USER unset, dev mode
Error
same file, --prod
OK — the dev block is not in effect
same file, --schema dev_x
OK — the flag replaces the field
dev.schema: dev_${USER:-scratch}, USER unset
OK — schema is dev_scratch
vars.start_date: ${START}, unset
Error — vars are always in effect
SQL models keep Jinja {{ var() }} and {{ env_var() }}. They are not expanded with ${VAR}.
Naming in Dev vs Prod
Dev and prod names differ only by schema. The table name is the file name in both modes.
File Path
Model name
Prod table
Dev table (dev_fritz)
staging/stg_orders.sql
stg_orders
staging.stg_orders
dev_fritz.stg_orders
marts/core/dim_customers.sql
dim_customers
marts.dim_customers
dev_fritz.dim_customers
analytics/plausible/events.sql
events
analytics.events
dev_fritz.events
raw.sql
raw
public.raw
dev_fritz.raw
staging/country_codes.csv
country_codes
staging.country_codes
dev_fritz.country_codes
Model names are unique across the project, so one dev schema never has a collision.
Override Rules
No dev block in yml
Prod
dev block present in yml
Dev
--prod flag
Prod (ignores dev block)
--schema <name> flag
Dev with specified schema (overrides dev.schema)
--prod + --schema
Error — cannot combine --prod and --schema
--target <conn>
Overrides the resolved target in either mode
Dev Workflow Example
You can also use --schema with no dev block in the yml:
Selectors
Selectors control which models and seeds a build run includes. Use --select to include models and --exclude to remove them. Both accept comma-separated lists, and the result is the union of all patterns.
dim_customers
Name
Model name (the file name)
sling build run -s dim_customers
marts.dim_customers
Table
Prod table name
sling build run -s marts.dim_customers
stg_*
Glob
Match model names by glob pattern
sling build run -s "stg_*"
tag:daily
Tag
Match models with a specific tag
sling build run -s "tag:daily"
+fct_orders
Upstream
Model and all its upstream dependencies
sling build run -s "+fct_orders"
fct_orders+
Downstream
Model and all its downstream dependents
sling build run -s "fct_orders+"
+fct_orders+
Full graph
All upstream + model + all downstream
sling build run -s "+fct_orders+"
2+fct_orders
N-degree upstream
Model and N levels of upstream dependencies
sling build run -s "2+fct_orders"
fct_orders+1
N-degree downstream
Model and N levels of downstream dependents
sling build run -s "fct_orders+1"
staging/*
Path
Match models by relative file path
sling build run -s "staging/*"
stg_a-fct_b
Slice
All models between A and B in the DAG (inclusive)
sling build run -s "stg_a-fct_b"
Glob Patterns
Glob selectors match against model names (the filename without extension).
*
Any sequence of characters
stg_*
stg_orders, stg_customers
?
Any single character
stg_?rders
stg_orders
[abc]
Character class
stg_[oc]*
stg_orders, stg_customers
{a,b}
Alternation
{stg,dim}_customers
stg_customers, dim_customers
Wildcards can be anywhere in the pattern:
Glob with Graph Operators
Glob patterns work with all graph operators (+, N+, +N). The glob resolves first. Then the graph operator applies to every matched model, and Sling combines the results.
An exact model name that does not exist gives an error. A glob that matches nothing gives an empty result and no error.
Path / Folder Selectors
Any selector with a / matches against the model's relative file path from the project root. This is useful to select all models in a folder, which usually maps to a database schema.
Given this project structure:
staging/*
stg_orders, stg_customers, country_codes
marts/core/*
dim_customers, fct_orders
marts/finance/*
revenue
marts/**/*
dim_customers, fct_orders, revenue
Combining and Excluding
--exclude applies after --select, and uses the same pattern syntax.
Default Behavior
No
--select= all models and seeds are selected--no-seeds= seeds are skipped from execution, but downstream models still runModels with
enabled: falsenever enter the DAG, so you cannot select themTags match models only. A
tag:selector never matches a seed
List Mode
Use sling build list to preview which models are selected, with no execution.
This respects --select and --exclude. Without a target, the table column is omitted and the file path is shown instead.
Compile Mode
Use sling build compile to see the DAG execution order and the compiled SQL for each selected model.
Compile mode checks that all templates compile and all references resolve. It connects to the target only when it must resolve an incremental watermark.
JSON Output
Add --json to compile or list for machine-readable output:
The payload has this shape:
Sub-projects produce a JSON array of these objects.
Nested Configs (Multi-Target)
Discovery is one level deep. Sling scans only the immediate subdirectories, and skips directories that start with ..
Inheritance
When a root sling_build.yml exists and child directories also have sling_build.yml files, -R makes each child config inherit from the root and override specific settings:
Merge rules for a child config:
vars— deep-merged, child wins on conflictdefaults.tags— union of parent and child, deduplicateddefaults.hooks— appended, parent hooks firstAll other
defaultsfields — child replaces parent when non-emptytarget,dev,dbt_project— child replaces parent when non-empty
Without -R, Sling applies only the root sling_build.yml and ignores the child overrides.
Independent Builds (Multi-Target)
When there is no root sling_build.yml but child directories each have their own, -R treats them as independent build projects that run in parallel:
Each sub-project compiles and executes independently against its own target. Sling limits concurrent sub-projects to the --threads value, and collects errors from all of them.
Without -R, this layout has no root sling_build.yml and no discovered child configs, so sling build prints the help menu instead of running. Pass -R or add a root config.
Last updated
Was this helpful?