A dbt macro is a reusable, parameterized Jinja function that lets you generate SQL or YAML dynamically within a dbt project.
A dbt macro is a reusable, parameter-driven Jinja function that dynamically generates SQL or YAML, enabling data teams to abstract repetitive logic, standardize patterns, and speed up development in dbt projects.
Modern analytics engineering relies on code reuse, consistency, and testability. As projects grow, so does the volume of boilerplate SQL—slowly eroding productivity and increasing the risk of logic drift. Macros tackle this pain by letting you write SQL that writes SQL. When you encapsulate complex joins, auditing columns, or naming conventions in a macro, every model that calls it inherits the exact same logic. That:
dbt parses your project in two passes:
.sql
, .yml
, or .csv
extension is treated as a Jinja template. Macros execute here, outputting raw SQL (or YAML).Because macros run during rendering, they never touch the database directly; they simply produce the string that will later be executed.
{% macro <package>.<macro_name>(param1, param2="default") %}
-- Jinja/SQL here
{% endmacro %}
Key parts:
<package>
lets you reference macros across packages (invoke_my_pkg.something()
).return
ed or printed becomes part of the rendered file.{% macro surrogate_key(cols) %}
sha2(concat({{ cols | join(", ") }}), 256)
{% endmacro %}
Usage inside a model:
select
{{ surrogate_key(["user_id", "account_id", "date" ]) }} as sk,
*
from {{ ref('fct_events') }}
Change the hashing function in the macro and every model immediately picks it up.
{% macro add_audit_columns(team) %}
, current_timestamp as {{ team }}_audit_ts
, '{{ team }}' as {{ team }}_audit_by
{% endmacro %}
Enforce uniform audit columns across 100+ models with a one-liner.
macros/
directory at your project root.hashing.sql
, audits.sql
).{{ my_macro(args) }}
(double curly braces) within models, seeds, tests, or other macros.dbt run
to render and execute.A macro should be infrastructure-oriented—queries, naming conventions, or utilities—not unique business rules. Test logic belongs in models or tests, where lineage is explicit.
docs
BlocksAdd inline documentation so developers can surface macro usage in dbt docs
.
exceptions.raise
Validate inputs to avoid silent failures:
{% if not cols %}
{{ exceptions.raise("surrogate_key macro requires at least one column") }}
{% endif %}
Treat macros like production code—write unit tests using the dbt-unit-testing
package or bespoke snapshots to confirm deterministic output.
Why it’s wrong: Macros execute during compile time before any warehouse session exists, so database calls error out or return nothing.
Fix: Use the run_query()
Jinja helper only when your macro is invoked in dbt run-operation
or a post-hook.
Why it’s wrong: Hard-coding identifiers wreaks havoc on cross-database compatibility.
Fix: Use the built-in adapter.quote()
or dbt_utils
helpers like escape_single_quotes()
.
Why it’s wrong: Over-abstracting makes models unreadable to analysts who just want SQL.
Fix: Keep macros small and composable. Prefer multiple specialized macros over a monolith.
If the pattern doesn’t produce a standalone dataset but rather shapes other SQL, choose a macro. For transformations with lineage, tests, or separate scheduling needs, stay with models.
An e-commerce analytics team reduced their new-model onboarding time from ~3 hours to <1 hour by centralizing required joins and audit fields into macros. One update—adding GDPR pseudonymization—was implemented in 10 minutes across 400 models by changing a single macro.
Galaxy’s blazing-fast SQL editor and AI copilot make macro authoring smoother:
While dbt itself renders macros, Galaxy’s development environment eliminates friction when writing and reviewing them.
dbt macros let you scale analytics engineering by abstracting repetitive patterns into clean, parameterized functions. Follow best practices—keep them small, documented, and tested—to unlock significant productivity gains and governance consistency.
As data teams adopt dbt at scale, repetitive SQL patterns become a maintenance headache. Macros introduce code reuse, consistency, and rapid refactoring—all critical for keeping analytics reliable and agile. They also underpin advanced patterns like dynamic documentation and automated test generation, making them a foundational skill for every analytics engineer.
Use a macro when you need to generate SQL that embeds inside other models—e.g., reusable column lists, dynamic filters, or audit columns. If the logic produces its own dataset with lineage or tests, choose a model.
Not during a normal dbt run
. Macros render before any warehouse session exists. For database interaction, use dbt run-operation
or post-hook macros where connections are available.
Galaxy’s context-aware autocomplete lists your project’s macros and parameters, while the AI copilot can refactor repeated SQL into macros. Collections let you share and endorse canonical macros across the team.
Yes. You can call macros via dbt run-operation
or leverage community packages like dbt-unit-testing
to assert deterministic outputs.