For the complete documentation index, see llms.txt. This page is also available as Markdown.

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_map

Naming 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 = public schema (default)

File Path
Schema
Model name
Full Table Name

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).

Model names must be unique across the project. Two events.sql files in different folders are an error:

Rename one file, or use one file with a different name.

File Classification

Extension
Classification
Notes

.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

Key
Type
Default
Description

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.

Key
Type
Default
Description

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

engine, range, rewrite, and tests are model-only keys. You cannot set them in defaults.

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:

  1. Model front-matter database:.

  2. dev.database in dev mode.

  3. defaults.database from the effective config.

  4. 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.

Mode
Schema Behavior
When Active

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.schema is mandatory when dev is present

  • dev.target is optional. If you do not set it, Sling uses the top-level target

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:

Situation
Result

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

Condition
Effective Mode

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.

Pattern
Type
Description
Example

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).

Wildcard
Meaning
Example
Matches

*

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:

Path selector
Matches

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 run

  • Models with enabled: false never enter the DAG, so you cannot select them

  • Tags 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)

Nested-config discovery is opt-in with -R / --recursive. By default, sling build run <path> loads only <path>/sling_build.yml and ignores any sling_build.yml files in subdirectories. Pass -R to enable the inheritance and multi-target behavior below.

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 conflict

  • defaults.tags — union of parent and child, deduplicated

  • defaults.hooks — appended, parent hooks first

  • All other defaults fields — child replaces parent when non-empty

  • target, 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.

Last updated

Was this helpful?