dbt

dbt var() and Project Variables: A Runtime Parameter Design Guide (for Analytics Engineers)

2026-04-19
NicheeLab Editorial Team

dbt's var() is a runtime parameter resolved at Jinja compile time. Use it to flexibly switch model and macro branching, thresholds, and date boundaries.

This article organizes variable precedence, design principles, concrete implementations, validation, and operations from both an exam (dbt Analytics Engineer) and a real-world perspective.

var() Basics and Precedence

var('name', default) is a variable reference resolved at Jinja compile time. Without a default, a missing variable produces a compile error. With a default, the build continues using that explicit fallback value when the variable is not set.

Variables are mainly set in the vars block of dbt_project.yml or via the CLI --vars flag. If the same key exists in both places, the CLI value wins. When a package references var(), you can override it by placing a value under the package's namespace in the root project's dbt_project.yml.

  • Resolution timing: at compile time (before SQL generation)
  • Main locations: the vars block of dbt_project.yml and the CLI --vars flag
  • Behavior when undefined: no default -> compile error; with default -> the default is used
  • Precedence (high -> low): CLI --vars > root project's dbt_project.yml vars > var()'s default
  • Package variables: override by setting values under a namespace keyed by the package name in the root dbt_project.yml
LocationExamplePriorityTypical use
CLI --varsdbt run --vars "{start_date: '2024-01-01', use_new_logic: true}"HighestTemporary overrides, CI/CD switching
dbt_project.yml vars (root)vars:\n start_date: '2021-01-01'\n use_new_logic: falseMediumCentralized defaults and team-wide standards
Package variable overridevars:\n some_package:\n enable_feature: trueMedium (scoped to the target package)Overriding default behavior of external packages
var()'s default{{ var('start_date', '1900-01-01') }}LowestSafe fallback that avoids compile errors

Design Principles: How to Choose Runtime Parameters

Variables should be "minimal and explicit." Limit runtime parameterization to thresholds and switches you want to change frequently without a redeploy. Too many variables explode the test matrix.

Types and naming directly affect long-term maintainability. Be explicit about types (booleans, dates, numbers, enums) and set defaults to safe, testable, least-privilege values.

  • Centralize: gather defaults in dbt_project.yml's vars block so changes are reviewable in version history
  • Explicit defaults: always provide a default to var() so undefined behavior is stable
  • Naming conventions: standardize on is_/use_ for flags, *_threshold for thresholds, *_date for dates
  • Type consistency: booleans must be true/false (not strings); normalize dates to 'YYYY-MM-DD'
  • Testing strategy: for key variables, verify the main combinations (e.g., use_new_logic true/false) at least once each in CI
  • Separation of concerns: read sensitive values via env_var, not var (credentials belong in profiles.yml)

Implementation: Using dbt_project.yml and Jinja Together

Below is a minimal example that defines defaults in dbt_project.yml and uses var() inside a model to toggle conditional logic and date boundaries. CI overrides them temporarily via CLI --vars.

When embedding date literals in SQL, quote and cast appropriately for your dialect (TO_DATE on Snowflake, DATE() on Databricks, etc.).

  • Place defaults in dbt_project.yml
  • Reference var() in the model and always pass a default
  • Override with --vars in CI/CD

Example linking dbt_project.yml, the model, and the CLI

# dbt_project.yml(抜粋)\nname: my_project\nversion: 1.0.0\nconfig-version: 2\n\nvars:\n  start_date: '2021-01-01'\n  use_new_logic: false\n\nmodels:\n  my_project: {+materialized: table}\n\n---\n-- models/fct_orders.sql(抜粋)\n{{ config(materialized='table') }}\n\nwith src as (\n  select * from {{ ref('stg_orders') }}\n  {% if var('use_new_logic', false) %}\n    where updated_at >= '{{ var('start_date', '1900-01-01') }}'\n  {% endif %}\n)\n\nselect * from src\n\n---\n# 一時的に上書き(CI など)\n# Linux/macOS の例(シェルでクォートに注意)\ndbt build --vars "{use_new_logic: true, start_date: '2024-01-01'}"

Package Variables and Namespace Overrides

When an external package (e.g., dbt-utils) references var(), you can override its behavior by creating a namespace named after the package in the root project's dbt_project.yml and defining keys underneath it.

This is the standard, safe way to change a package's default behavior. Record any overrides in the README so you can review diffs when upgrading the package.

  • The namespace key must match the package name in packages.yml
  • If project-level vars conflict, the override only affects the namespace seen by callers (var() calls inside the package)
  • Remove unnecessary overrides and keep the set minimal so diffs remain readable

Example of overriding package variables (dbt_project.yml)

vars:\n  some_package:\n    enable_feature: true\n    threshold: 10

Validation, Guards, and Type Gotchas

For important variables, validating allowed values at compile time is safer. It fails fast when unexpected values slip in and prevents incorrect SQL from running. In dbt you can fail explicitly with exceptions.raise_compiler_error.

Jinja truthiness follows Python, so a non-empty string like "false" evaluates as truthy. Always pass booleans as the boolean type, and on the CLI quote them so that true/false are interpreted as YAML.

  • Enum validation: check membership in the allowed-value set
  • Pass booleans as booleans (no strings)
  • Watch for implicit string casts in numeric comparisons (use |int or |float for explicit conversion as needed)
  • Debug: emit to the build log via {{ log('var x=' ~ var('x', 'n/a'), info=True) }}

Example macro that guards at compile time

{% macro require_valid_choice(var_name, allowed) %}\n  {% set value = var(var_name, none) %}\n  {% if value is none or value not in allowed %}\n    {{ exceptions.raise_compiler_error(var_name ~ ' must be one of ' ~ (allowed | join(', ')) ~ ', but was: ' ~ (value|string)) }}\n  {% endif %}\n{% endmacro %}\n\n-- 利用例(モデル先頭など)\n{{ require_valid_choice('region', ['us', 'eu', 'ap']) }}

Operations: Per-Environment Overrides and CI/CD

Handle behavior differences across environments (dev/stg/prod) primarily through connection profiles and target, and use var only for the parts of business logic that should vary. In CI, validate the main combinations via --vars.

The diagram below illustrates the var resolution flow. CLI wins if present; otherwise dbt_project.yml is consulted; finally the default is used, and the resolved value lands in the compiled SQL.

  • CI: run dbt build at least once each with the key flags set to true and false
  • Operations: keep steady-state values in dbt_project.yml; use --vars for temporary deploy-time changes
  • Auditing: review variable changes via PR and record the impact in the CHANGELOG

var resolution flow (precedence and propagation path)

(1)(2)(4)(3)CLI --vars(1) Highest prioritydbt compiler / JinjaVariable resolutionGenerated SQLRuns on the DWH, returns resultsdbt_project.yml vars(2) Defaultsvar()'s default(4) FallbackPrecedence: (1) CLI --vars > (2) dbt_project.yml vars > (4) var()'s default

Example for GitHub Actions (verifying the key flag in both states)

jobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with: { python-version: '3.11' }\n      - run: pip install dbt-core dbt-snowflake\n      - name: Build (use_new_logic=false)\n        run: dbt build --vars "{use_new_logic: false, start_date: '2021-01-01'}"\n      - name: Build (use_new_logic=true)\n        run: dbt build --vars "{use_new_logic: true, start_date: '2024-01-01'}"

Check Your Understanding

Analytics Engineer

問題 1

A model references {{ var('start_date', '1900-01-01') }}. dbt_project.yml sets start_date: '2021-01-01', and at runtime you pass dbt run --vars "{start_date: '2022-01-01'}". Which value is actually used?

  1. A. '1900-01-01'
  2. B. '2021-01-01'
  3. C. '2022-01-01'
  4. D. Empty string (unset)

正解: C

var precedence is CLI --vars > dbt_project.yml vars > var()'s default. Therefore '2022-01-01' is used.

Frequently Asked Questions

What is the difference between vars and env_var, and which should I use?

vars handle runtime parameters for business logic (flags, thresholds) and are configured in dbt_project.yml or via CLI --vars. env_var is a function that reads environment variables and is the right choice for sensitive values like credentials, secrets, and connection targets. Use env_var, not vars, for sensitive data.

Can I put vars in profiles.yml?

No. vars are managed in the vars block of dbt_project.yml and via CLI --vars. profiles.yml is where you define connection information (account, user, role, warehouse, etc.) and should not contain business-logic parameters.

How are --vars values typed?

They are parsed as YAML/JSON. true/false are booleans, numerics are numbers, and strings must be quoted. Example: dbt run --vars "{use_new_logic: true, threshold: 10, start_date: '2024-01-01'}". Be careful: passing the string 'false' is evaluated as truthy.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
dbt

dbt Models: SQL-Defined Transformation Units (2026)

Model fundamentals — SELECT-based definitions, naming, refs,...

dbt

dbt Analytics Engineering Exam: Complete Guide (2026)

Pass the AE Certification — scope, weighting, sample questio...

dbt

dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)

Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...

dbt

dbt Project Structure: models/seeds/macros Layout (2026)

Recommended dbt project layout — models, seeds, macros, snap...

dbt

dbt_project.yml Explained: Every Config (2026)

Every dbt_project.yml setting that matters — paths, vars, ma...

Browse all dbt articles (101)
© 2026 NicheeLab All rights reserved.