Rules
Overview
Turn repeated SQL and project review decisions into compiler-enforced requirements.
Code review is an expensive place to keep enforcing a decision the team has already made.
Comments such as these are useful once, but repetitive after that:
- “This query needs deterministic ordering before
LIMIT.” - “Move this model into the agreed area and layer.”
- “Final models cannot depend on another area’s private intermediate models.”
- “This incremental output needs a declared grain, an enforced contract, and a focused test.”
- “External sources must enter through staging.”
Rules turn those decisions into configurable compile-time requirements. They run over the same project representation SQLBuild uses to produce executable artifacts, so a failed Rule is a failed compile rather than an optional report somebody must remember to run.
What Rules are for
Section titled “What Rules are for”Start with built-in Rules, then add custom Rules for requirements specific to your project.
- Built-in Rules are opinionated, reusable checks for areas such as SQL safety, contracts, and dependency boundaries. Select or ignore each Rule individually.
- Custom Rules encode local decisions such as directory structure, architectural boundaries, public interfaces, or the contract and test coverage required for a particular kind of model.
Both evaluate authored SQL and the compiled project without querying warehouse data. They use compiler-owned facts about SQL, models, paths, configuration, columns, contracts, tests, audits, declarations, and dependencies.
That context can be combined in one check—for example, allowing SELECT * in staging while requiring
contracted outputs in final models, or allowing cross-area dependencies only through an interface
model.
How Rules work
Section titled “How Rules work”Use sqb rules show to understand a Rule before enabling it:
sqb rules show SQLCLEAN004SQLCLEAN004: Row selection is nondeterministicFamily: SQLCLEANSlug: unordered-limitSubject: modelEnabled by default: yesRemediation: Add ORDER BY with a deterministic tie-breaker before LIMIT or OFFSET.Enabled by default means the Rule runs when select is unset. Without select, SQLBuild runs
the default SQL Rules and no other configurable Rules.
Select Rules in sqlbuild_project.toml. This example enables the complete built-in SQL family:
[rules]select = ["SQLCLEAN"]An exact code such as SQLCLEAN004 selects one Rule. A family code such as SQLCLEAN selects every
Rule in that family, including Rules that are not enabled by default. To run no configurable Rules, set
select = []; to turn off only the SQL Rules, add SQLCLEAN to ignore. Mandatory compiler
correctness still applies.
Now consider a model that returns an arbitrary row because its LIMIT has no ordering:
-- models/orders.sqlSELECT order_id FROM orders LIMIT 1Run normal compilation:
sqb compileThe selected Rule reports the source location, problem, and remediation:
error[SQLCLEAN004]: Row selection is nondeterministic --> models/orders.sql:2:36 | 2 | SELECT order_id FROM orders LIMIT 1 | ^ = help: Add ORDER BY with a deterministic tie-breaker before LIMIT or OFFSET.Compilation fails before SQLBuild completes artifacts or opens a warehouse connection. Add deterministic ordering and compile again:
SELECT order_id FROM orders ORDER BY order_id LIMIT 1Use focused commands when discovering or adopting Rules:
sqb rules listsqb rules run SQLCLEAN004A focused run checks only the requested Rule or family. Run sqb compile before treating the whole
project as valid.
SQL Rules
Section titled “SQL Rules”SQL linting is part of the Rules system rather than a separate command. The SQL Rules come from
SQLClean, the SQL linter and formatter SQLBuild runs on every SQL body.
They have the same codes, defaults, findings and fixes as in the sqlclean command; see the
SQLClean Rule reference.
The SQLCLEAN family covers deterministic SQL diagnostics such as:
- unsafe
NULLcomparisons; - implicit cartesian joins;
- unordered
LIMITandOFFSET; - unused CTEs;
- duplicate aliases;
- unstable window ordering;
- risky set-operation shapes;
- selected SQL structure and convention requirements.
These checks run through ordinary compilation. There is intentionally no separate sqb lint
lifecycle. If an SQL requirement affects whether the project is acceptable, the compiler enforces
it with the rest of the configured Rules.
Not every traditional lint concern should become a diagnostic. SQLBuild separates three kinds of SQL responsibility:
| Responsibility | Owner | Example |
|---|---|---|
| Correctness required to understand the project | Compiler | Invalid syntax, unresolved references, incompatible output shape |
| Configurable, deterministic requirements | SQLCLEAN Rules (executed by the compiler) |
Unordered LIMIT, unused CTE, implicit cartesian join |
| Canonical presentation | sqb format (separate from the compiler) |
Capitalization, indentation, spacing, comma and clause layout |
Rules never rewrite source. sqb format rewrites source and does not decide whether a project
passes its configured Rules. This keeps diagnostics and source mutation separate.
Built-in and custom Rules
Section titled “Built-in and custom Rules”SQLBuild maintains native built-in Rules for reusable requirements. SQL Rule codes begin with
SQLCLEAN, for example SQLCLEAN004. Rules that read the project, such as SQBRGRAPH101, begin
with SQBR.
Projects can define custom Python Rules under rules/**/*.py. Their codes begin with XSQBR, for
example XSQBRARCH001. Custom Rules use the same selection, findings, exceptions, execution order,
and cache system as built-ins.
[rules]select = [ "SQLCLEAN", "SQBRGRAPH", "XSQBRARCH",]Define typed model or project checks over compiler-owned facts with @rule, RuleContext, and
Finding.
Dialect support
Section titled “Dialect support”SQL Rules, and the built-in Rules that read SQL, such as SQBRMODEL102 and the SQL-test Rules
SQBRTEST201 to SQBRTEST203, run only where SQLBuild parses the project’s dialect. Built-in Rules
that read SQL support these adapters:
| Adapter | Built-in Rules that read SQL |
|---|---|
| DuckDB, MotherDuck | Supported |
| PostgreSQL | Supported |
| Snowflake | Supported |
| SQLite | Supported |
| BigQuery, ClickHouse, Databricks, SQL Server | Not yet |
Where SQLBuild does not parse the dialect yet, sqb compile and sqb rules run show L007
warnings that name it: one per file for SQL Rules, and one per model or SQL test listing the
built-in Rules that did not run. L007 never changes an exit code, including for sqb plan and
sqb build: it reports a gap in SQLBuild’s dialect support, not a problem in your SQL. A syntax
error in a supported dialect still fails the Rules that read it.
One definition of project validity
Section titled “One definition of project validity”sqb compile is authoritative. SQLBuild evaluates a project in this order:
mandatory compiler correctness→ selected native built-in Rules→ selected custom Python Rules→ artifact completionBuild and planning commands use the same compiler path. Configured findings stop execution before a warehouse connection is opened. Compile artifacts are not completed from a project that failed its Rules.
Rules compared with tests, audits, and contracts
Section titled “Rules compared with tests, audits, and contracts”Rules do not replace every form of validation:
| Capability | Question it answers |
|---|---|
| Mandatory compiler correctness | Can SQLBuild construct a trustworthy project and executable representation? |
| Rules | Does the authored and compiled project satisfy selected static requirements? |
| Contracts | Does a model declare and preserve the required output shape? |
| SQL tests | Does SQL logic produce an expected result for controlled inputs? |
| Audits | Does warehouse data satisfy a runtime quality requirement? |
| Runtime checks | Are external resources and execution state valid now? |
Use a Rule when the answer can be determined from source and compiler facts. Use a test when you need to execute SQL against controlled data. Use an audit when the answer depends on warehouse data.
Findings and intentional exceptions
Section titled “Findings and intentional exceptions”A finding contains a stable code, project-relative path, line, column, explanation, and remediation. This makes the same requirement usable in a terminal, JSON output, CI annotation, or agent workflow.
Intentional departures remain explicit and live only in sqlbuild_project.toml. Exact and
relation-level exceptions and path- or resource-scoped ignores require a reason; exceptions are
stale-checked so obsolete entries do not silently accumulate. There are no inline suppression
comments, and mandatory compiler correctness cannot be excepted at all.
See Findings and exceptions for configuration examples.
Performance is part of the design
Section titled “Performance is part of the design”Model Rules are evaluated and cached per model. Editing one model invalidates affected subjects rather than every invocation. Project Rules run once over the complete project view and are the explicit choice for genuinely project-wide requirements, with broader invalidation. SQLBuild tracks the inputs each Rule depends on so cached findings are reused only while those inputs remain valid.
The default SQL Rules lint every compiled model, so a cold compile without a cache costs more than
the compiler alone: about 14% more wall time and 28% more CPU on a generated 3,000-model project.
Warm and one-model edit compiles reuse cached findings and cost the same. Set select = [] to
measure or run the compiler without them.
Required CI exercises custom Rule packs over generated projects, checking compilation time, memory, and cache invalidation. Separate 20- and 100-Rule profiles measure the cost of custom validation at 5,000-model scale.
See Benchmarks for the benchmark profiles and reproduction commands, and Execution and caching for the Rules lifecycle.
Continue
Section titled “Continue”Select exact Rules or families and configure project-owned options.
Findings and exceptionsUnderstand diagnostics, exact exceptions, path ignores, and stale checks.
Published-layer RulesKeep each domain’s published layer free of consumer-specific variants.
Execution and cachingLearn evaluation order, focused execution, and dependency-aware reuse.
Rules CLIList, inspect, run, and generate guidance for configured Rules.