Skip to main content
Macros are Python functions that generate SQL fragments at compile time. Instead of Jinja templates, you write real Python - testable, debuggable, and composable with standard tooling. For the full picture of how macros fit into SQLBuild’s interpolation system, see Interpolation.

Defining macros

Create Python files under macros/ in your project. Every public function in a macro file becomes a callable macro:
Macros can accept any Python arguments (strings, numbers, lists, dicts, booleans) and must return a SQL string when called from SQL.

Using macros in models

Call macros in model SQL using the @macro_name(args) syntax:
At compile time, @cents_to_dollars('SUM(p.amount_cents)') expands to ROUND(CAST(SUM(p.amount_cents) AS DOUBLE) / 100, 2).

Using macros in tests

Because unit tests are written in SQL, they support macro calls. This is useful for reusable mock data generators:

Using macros in hooks

Macros are expanded inside sql(...) hook entries in pre_hooks and post_hooks:
Hook SQL is validated at compile time, so invalid hook SQL is caught before execution. SQL hooks also support @@CTX: context variables, @@name project variables, and @@ENV:NAME environment variables directly without needing a macro wrapper. For hooks that need more than string interpolation, use python(...) hooks instead. See Hooks for the full Python hook API.

Macro context

When a macro function accepts a ctx parameter as its first argument, SQLBuild passes a MacroContext object with adapter and target information:
The macro context provides:

Macro arguments

Macro arguments use Python literal syntax. Supported types:
  • Strings: 'value' or "value"
  • Numbers: 42, 3.14, -1
  • Booleans: True, False
  • Lists: [1, 2, 3]
  • Dicts: {'key': 'value'}
  • None: None
  • Nested macro calls: @other_macro('arg')
Keyword arguments are supported:

Nested macro calls in arguments

Macros can be passed as arguments to other macros. The inner macro evaluates first and its result becomes an argument to the outer macro:
You can mix regular arguments with nested macro calls:
Inner macros used as arguments don’t have to return strings - they can return any Python object that the outer macro accepts.

Composing macros

Macro output cannot contain macro calls. Expansion is single-pass: if a macro returns SQL containing @another_macro(), SQLBuild raises an error. If you need composition, compose in Python:

Where macros are allowed

  • Model query SQL - the SELECT statement after the MODEL() header
  • Hook strings - sql(...) entries in pre_hooks and post_hooks in MODEL() config
  • Test SQL - unit test CTE bodies
  • Audit SQL - singular audit queries
Macros are not allowed in MODEL() config values (other than SQL hook entries). If a config field contains @macro(), SQLBuild raises a compile error.

Discovery rules

  • SQLBuild discovers all .py files under macros/ recursively
  • Every public function (not starting with _) becomes a macro
  • Macro names must be unique across all macro files - duplicates raise a compile error
  • Macros are loaded once at compile time, not per-model