dbt Targets and Environments

A target in dbt is a named database configuration defined in profiles.yml. Targets let you run the same dbt project against different databases or schemas — typically a development environment for testing and a production environment for live data. Switching environments changes where dbt writes output without changing any SQL code.

What a Target Is

profiles.yml structure:

my_project:
  target: dev           ← default target when none specified
  outputs:
    dev:                ← target named "dev"
      type: snowflake
      schema: dbt_dev
      ...
    prod:               ← target named "prod"
      type: snowflake
      schema: dbt_prod
      ...
    ci:                 ← target named "ci"
      type: snowflake
      schema: "dbt_ci_{{ env_var('GITHUB_RUN_ID') }}"
      ...

Switching Targets

# Use the default target (dev in the example above)
dbt run

# Use a specific target
dbt run --target prod
dbt run --target ci
dbt test --target prod
dbt build --target ci

How Targets Separate Environments

Same SQL:
  select * from {{ ref('stg_orders') }}

Target dev:
  → reads from  dbt_dev.stg_orders
  → writes to   dbt_dev.fct_orders

Target prod:
  → reads from  dbt_prod.stg_orders
  → writes to   dbt_prod.fct_orders

Your SQL never changes. The target determines the schema prefix applied to all model names.

target Object in Jinja

The target object is available in all Jinja contexts and exposes the current target's properties:

{{ target.name }}       → 'dev', 'prod', 'ci'
{{ target.schema }}     → 'dbt_dev', 'dbt_prod'
{{ target.database }}   → 'ANALYTICS'
{{ target.type }}       → 'snowflake', 'bigquery', 'postgres'
{{ target.threads }}    → 4, 8
{{ target.profile_name }} → 'my_project'

Environment-Specific SQL Logic

-- Limit rows in dev to speed up development runs
select *
from {{ source('analytics', 'raw_events') }}
{% if target.name != 'prod' %}
  where event_date >= dateadd(day, -7, current_date)
  -- Dev only loads last 7 days (not 3 years of history)
{% endif %}
-- Use a mock table in dev, real table in prod
{% if target.name == 'prod' %}
  from {{ ref('fct_orders') }}
{% else %}
  from {{ ref('fct_orders_dev_sample') }}   ← smaller, faster sample
{% endif %}

Custom Schema Per Target

Each developer can work in their own personal schema by customizing the schema field:

my_project:
  target: dev
  outputs:
    dev_alice:
      type: postgres
      schema: dbt_alice
      ...
    dev_bob:
      type: postgres
      schema: dbt_bob
      ...
    prod:
      type: postgres
      schema: analytics
      ...

Three-Environment Setup (Standard Pattern)

Environment   Target Name   Schema          Purpose
-----------   -----------   ------          -------
Development   dev           dbt_[username]  Individual developer testing
CI            ci            dbt_ci_[run_id] Automated tests on pull requests
Production    prod          analytics       Live data for dashboards
# Local development
dbt build --target dev

# CI pipeline (GitHub Actions, etc.)
dbt build --target ci

# Production deployment
dbt build --target prod

generate_schema_name Macro

By default, dbt appends the custom schema suffix to your target schema. A model with +schema: finance in a dev environment with schema dbt_dev writes to dbt_dev_finance. Override this with the generate_schema_name macro in production to write to just finance:

-- macros/generate_schema_name.sql
{% macro generate_schema_name(custom_schema_name, node) -%}
    {%- set default_schema = target.schema -%}
    {%- if custom_schema_name is none -%}
        {{ default_schema }}
    {%- elif target.name == 'prod' -%}
        {{ custom_schema_name | trim }}   ← production uses clean schema name
    {%- else -%}
        {{ default_schema }}_{{ custom_schema_name | trim }}  ← dev prefixes
    {%- endif -%}
{%- endmacro %}
Result in dev:   dbt_dev_finance
Result in prod:  finance

Verifying Your Active Target

dbt debug

Output includes:
  target: dev
  profile: my_project
  output: dev
  schema: dbt_dev
  connection test: OK

Leave a Comment

Your email address will not be published. Required fields are marked *