Concepts
Project Configuration
Configure your SQLBuild project with sqlbuild_project.toml and sqlbuild_local.toml.
SQLBuild projects are configured with two files in the project root:
sqlbuild_project.toml- shared project configuration, committed to version controlsqlbuild_local.toml- local developer overrides, gitignored
Macro, constant, and enum visibility is not configured in either file. Declaration scopes use filesystem conventions; see Declaration Scopes.
Most projects need only one committed sqlbuild_project.toml. Define shared targets such
as dev and prod there, including clone policies and team-wide defaults. Do not maintain
separate complete project files for each environment.
Create sqlbuild_local.toml only when a developer or execution environment needs different
target selection, credentials, schemas, adapter settings, or variables. SQLBuild loads it
automatically and merges its explicitly configured values over the shared project config.
project/ sqlbuild_project.toml # committed: shared targets and behavior sqlbuild_local.toml # gitignored: this developer's overridesAdd the local file to .gitignore:
sqlbuild_local.tomlsqlbuild_project.toml
Section titled “sqlbuild_project.toml”A complete example:
name = "waffle_shop"adapter = "duckdb"default_target = "dev"
[connections.local]database = "waffle_shop_control.duckdb"
[settings]default_audit_severity = "warn"
[defaults]materialized = "table"
[constants]collection_rendering = "value_list"
[targets.prod]connection = "local"schema = "prod"
[targets.dev]connection = "local"schema = "dev"
[path_defaults.staging]materialized = "view"Required fields
Section titled “Required fields”| Field | Description |
|---|---|
name |
Project name. Used in fingerprint tracking and manifest generation. |
adapter |
Database adapter: duckdb, motherduck, snowflake, bigquery, databricks, postgres, or sqlserver. See Adapters. |
default_target |
Name of the target to build against when none is selected (see Targets). |
Named connections
Section titled “Named connections”Define reusable connections under [connections.<name>], then reference one by name from
each target. Connections own endpoint, authentication, and compute settings. Targets own the
authoritative database, schema, variables, and operational policy.
[connections.local]database = "my_project.duckdb"
[targets.dev]connection = "local"schema = "dev"Multiple targets can reuse one connection while keeping separate namespaces and policies:
[connections.warehouse]account = "my_org-my_account"user = "${ENV:SNOWFLAKE_USER}"password = "${ENV:SNOWFLAKE_PASSWORD}"warehouse = "TRANSFORM_WH"
[targets.prod]connection = "warehouse"database = "ANALYTICS"schema = "PROD"
[targets.dev]connection = "warehouse"database = "ANALYTICS"schema = "DEV_ALICE"A database or schema present in a named connection is connection/session metadata only;
it does not satisfy the mandatory namespace strategy for a named target. Put the target’s
authoritative database and schema on [targets.<name>]. SQLBuild validates connection
references while loading configuration, without opening a warehouse connection, and reports
an unknown targets.<name>.connection name as an offline configuration error.
For migration only, SQLBuild still maps legacy [connection] to an implicit connection and
legacy [targets.<name>.connection] blocks to target-specific implicit connections. These
forms are compatibility syntax, not the canonical format for new or updated projects.
Targets
Section titled “Targets”A target is a named build context - the database and schema you build into, plus execution policy (for example dev and prod). Each target references a named connection and can configure:
| Field | Description |
|---|---|
schema |
Schema for all models in this target; required for named targets |
loader_schema |
Default write schema for managed source loaders; falls back to schema |
database |
Database for all models in this target |
connection |
Name from [connections.<name>] used for endpoint, authentication, and compute |
vars |
Target-specific project variables |
defer_sources_to |
Target name to read managed source data from (see Loaders) |
clone |
Clone policy (see below) |
[connections.warehouse]account = "my_org-my_account"warehouse = "TRANSFORM_WH"
[targets.prod]connection = "warehouse"database = "analytics"schema = "analytics_prod"loader_schema = "raw_prod"defer_sources_to = "prod"
[targets.dev]connection = "warehouse"database = "analytics"schema = "analytics_dev"loader_schema = "raw_dev"defer_sources_to = "prod"
[targets.staging]connection = "warehouse"database = "analytics"schema = "staging"Managed loader writes use the active target’s loader_schema, falling back to its model
schema. Managed source reads use the target named by defer_sources_to, or the active
target itself when deferral is omitted. In the example, load --target dev writes to
raw_dev, while models built in dev read from raw_prod.
SQLBuild rejects targets on the same warehouse/database when their managed loader writes resolve to the same schema. Two targets may read the same schema through deferral, but they cannot both own loader writes there.
Selecting a target
Section titled “Selecting a target”The active target is determined by (in order of precedence):
--targeton the command line (highest priority)sqlbuild_local.tomltargetfielddefault_targetinsqlbuild_project.toml- No target (models build to the default schema)
A typical developer keeps shared target definitions in sqlbuild_project.toml and selects
their normal target once in the optional local file:
target = "dev"
[targets.dev]connection = "warehouse"schema = "dev_alice"loader_schema = "raw_alice"
[connections.warehouse]user = "alice"password = "${ENV:SNOWFLAKE_PASSWORD}"Commands then use dev automatically. An explicit command such as sqb build --target prod
still takes precedence for that invocation.
Clone policies
Section titled “Clone policies”Targets can declare whether they allow cloning to or from:
[targets.prod]schema = "prod"
[targets.prod.clone]allow_as_clone_origin = trueallow_as_clone_destination = false
[targets.dev]schema = "dev"
[targets.dev.clone]allow_as_clone_origin = falseallow_as_clone_destination = trueBoth policies default to false. sqb clone --from prod --to dev requires allow_as_clone_origin = true on prod and allow_as_clone_destination = true on dev.
Defaults
Section titled “Defaults”Project-wide model defaults. Any field you can set in a MODEL() header can be set here as a default:
[defaults]materialized = "table"incremental_strategy = "delete_insert"replay_on_change = "full"tags = ["managed"]These apply to all models unless overridden by path defaults or the model’s own MODEL() header.
Constants
Section titled “Constants”Collection constants default to parenthesized SQL value lists. Set a project-wide default when lists and sets should instead compile to first-class adapter-native arrays:
[constants]collection_rendering = "array"collection_rendering accepts value_list (the SQLBuild default) or array. A public constant’s render_as field or a model-local constant(...) wrapper overrides the project setting. The complete precedence order is declaration override, project setting, then value_list.
This setting does not make unsupported adapter features portable. In particular, SQL Server rejects native arrays, and BigQuery rejects nested arrays. See Collections and Rendering for syntax, adapter output, and value-list usage constraints.
Path defaults
Section titled “Path defaults”Per-directory model defaults. Useful for applying different config to different parts of your project:
[path_defaults."models/staging"]materialized = "view"tags = ["staging"]
[path_defaults.marts]materialized = "table"tags = ["marts"]replay_on_change = "full"Path matching uses the path below models/. A model at models/staging/stg_orders.sql matches the
staging path default.
Config layering order
Section titled “Config layering order”Configuration is layered in this order, with later layers overriding earlier ones:
- Project defaults (
defaults) - Path defaults (
path_defaults) - if the model’s path matches - MODEL() header - the model’s own config
Most keys are overridden by the more specific layer, but three merge instead:
tagsare unioned across layers. A model withtags [marts]in its header that matches a path default withtags [managed]will have both tags.row_diff_exclude_columnslists are unioned across layers.row_diff_tolerancesmappings are deep-merged across layers, so a header tolerance for one column adds to (rather than replaces) tolerances declared in defaults or path defaults.
Diff sampling values use ordinary replacement precedence. row_diff_sample_rows = 0 explicitly
disables an inherited sample for a path or model. CLI --sample-rows, --sample-seed, and
--exhaustive override the compiled configuration for one invocation.
Settings
Section titled “Settings”Global feature toggles:
[settings]sql_analysis = truequery_change_tracking = truecolumn_contract_mode = "implicit"concurrency = 1microbatch_concurrency = falseauto_load_sources = truetable_promotion_mode = "staged"default_audit_severity = "warn"default_audit_run_scope = "final"| Field | Default | Description |
|---|---|---|
sql_analysis |
true |
Enable SQL syntax analysis, column binding, type inference, output inference, and semantic validation at compile time |
query_change_tracking |
true |
Track query fingerprints for change detection |
column_contract_mode |
implicit |
Controls whether column declarations on models without a contract declaration activate static shape/nullability validation. implicit preserves that validation; explicit treats columns as metadata and audit attachment unless the model declares contract enforced. Model-level contract enforced and contract none override this setting. Explicit type enforcement remains independent. See Contracts. |
concurrency |
1 |
Maximum parallel model execution (currently serial only) |
microbatch_concurrency |
false |
Explicitly permit models with batch_concurrency > 1; concurrent batches use immutable coordination facts |
auto_load_sources |
true |
Automatically run source loaders before building dependent models during sqb build. See Loaders. |
table_promotion_mode |
adapter default | staged (CTAS to staging, audit, then promote) or immediate (CTAS directly to target, then audit) |
default_audit_severity |
warn |
Default severity for audits: warn or error |
default_audit_run_scope |
final |
Default run scope for audits: final or delta_and_final |
Table promotion mode
Section titled “Table promotion mode”staged(default for most adapters): Materializes into a staging table, runs audits, then swaps into the target. If audits fail, the production table is untouched.immediate: Creates the table directly at the target location. Audits run after materialization. Simpler but no pre-promotion safety net.
Rules configuration belongs in the shared sqlbuild_project.toml so local and CI compilation use
the same checks:
[rules]select = ["SQBRSQL", "SQBRGRAPH", "XSQBRARCH"]Rules are opt-in. Exact codes activate individual checks and prefixes activate a family. Built-in
codes begin with SQBR; repository-defined codes begin with XSQBR. See
Compiler-integrated Rules for configuration, authoring, and suppressions.
Project variables
Section titled “Project variables”Variables are simple string substitutions available in model SQL via the @@name syntax:
[vars]schema_prefix = "analytics"retention_days = "90"Target-specific variables override project-level ones:
[vars]schema_prefix = "analytics"
[targets.prod.vars]schema_prefix = "prod_analytics"See Macros for details on variable substitution and how variables interact with macros.
Janitor
Section titled “Janitor”Configuration for the sqb janitor command, which archives and then deletes stale warehouse relations:
[janitor]enabled = falseretention_days = 14archive_retention_days = 14delete_tracked_only = trueexclude_patterns = ["audit_*", "tmp_*"]| Field | Default | Description |
|---|---|---|
enabled |
false |
Whether janitor is active |
retention_days |
14 |
How many days a relation must be stale before it is archived |
archive_retention_days |
14 |
How many days an archive is kept before it is deleted. 0 deletes it in the same run. |
delete_tracked_only |
true |
Only clean relations that appear in fingerprint tracking |
exclude_patterns |
[] |
Glob patterns for relations to skip |
direct_state_history_versions |
20 |
How many state-history rows to keep per identity in _sqlbuild_fingerprints and _sqlbuild_source_freshness |
See janitor for the archive and delete lifecycle.
Scenario
Section titled “Scenario”Configuration for scenario snapshot capture safety limits and local type overrides:
[scenario.snapshot_limits]max_rows_per_relation = 10000max_total_rows = 50000max_bytes_per_relation = 10485760max_total_bytes = 52428800| Field | Default | Description |
|---|---|---|
max_rows_per_relation |
none | Maximum rows per captured relation |
max_total_rows |
none | Maximum total rows across all relations in one scenario |
max_bytes_per_relation |
none | Maximum JSONL bytes per relation file |
max_total_bytes |
none | Maximum total JSONL bytes per scenario |
Local type overrides for DuckDB replay are configured per adapter dialect:
[scenario.local_type_overrides.snowflake]"OBJECT" = "JSON""ARRAY" = "JSON"See Scenarios for details on local type overrides and capture limits.
Configuration for running SQLBuild alongside an existing dbt project:
[dbt]project_dir = "../dbt_project"profiles_dir = "../profiles"target_path = "../dbt_project/target"target = "dev"| Field | Description |
|---|---|
project_dir |
Path to the dbt project root (where dbt_project.yml lives) |
profiles_dir |
Path to the directory containing profiles.yml |
target_path |
Path to dbt’s target/ directory (where manifest.json is written) |
target |
dbt target name override (optional) |
Paths can be absolute or relative to the SQLBuild project root. See Using SQLBuild with dbt for setup and usage details.
Skills
Section titled “Skills”Configuration for AI agent skill file installation:
[skills]targets = ["agents", "claude"]auto_update = false| Field | Default | Description |
|---|---|---|
targets |
["agents", "claude"] |
Agent targets to install. OpenCode consumes .agents; use opencode only as an explicit override. |
auto_update |
false |
Refresh stale SQLBuild-owned generated files from the installed package during normal commands; custom collisions are never overwritten. |
See skills CLI reference for usage details.
sqlbuild_local.toml
Section titled “sqlbuild_local.toml”Local developer overrides. This optional file is loaded automatically and should be gitignored. Only put values that differ from the shared project configuration here.
target = "dev"
[targets.dev]schema = "dev_alice"loader_schema = "raw_alice"
[connections.local]database = "my_local.duckdb"
[settings]sql_analysis = falseconcurrency = 4
[vars]debug_mode = "true"| Field | Description |
|---|---|
target |
Override which target is active for this developer |
adapter |
Override the database adapter (e.g. use DuckDB locally while prod uses Snowflake) |
connections |
Override named connection fields; entries merge by connection name |
settings |
Override global settings (only explicitly set fields take effect) |
vars |
Developer-specific variable overrides (merged on top of project + target vars) |
Project and local configuration merge named connections by name and merge their explicitly
configured fields. Target blocks merge the same way and may override the connection reference,
database, schema, loader_schema, variables, source deferral, and policy fields. Unspecified
values continue to come from sqlbuild_project.toml; a local reference to an unknown merged
connection still fails offline during configuration loading.
This replaces the common dbt pattern of switching profiles or setting environment variables
to change targets. Each developer sets their target, named connection, and preferences once in
sqlbuild_local.toml and it persists across sessions.