this is a dbt built-in variable that returns a Relation representing the node currently being compiled and executed (model, snapshot, test, hook, and so on).
This article walks through how this works, how it differs from ref/source, how to use it in incremental models, and the caveats in tests and run-operation — organized around the points most likely to appear on the exam.
this is a built-in variable available in the Jinja context that returns an adapter-specific Relation object pointing to the current node. At render time it expands to database.schema.identifier (with the adapter applying the appropriate quoting).
You can access this.database, this.schema, and this.identifier individually. It is available in models, snapshots, tests, and hooks, but using it inside an ephemeral model is discouraged because such models have no physical object and the meaning is ambiguous.
| Syntax | Purpose | Example rendered output |
|---|---|---|
| this | Points to the Relation of the current node | analytics.core.orders |
| ref('model_name') | Resolves dependent models and forms the DAG | analytics.staging.stg_customers |
| source('src', 'table') | References an external source table | raw.sales.customers |
| target | Metadata about the execution target (profile, schema, etc.) | dev (not a Relation) |
How Jinja renders this
Minimal example: referencing this attributes
-- models/demo_this.sql
-- At run time, inspect the components of the current model
select
'{{ this.database }}' as db,
'{{ this.schema }}' as sch,
'{{ this.identifier }}' as idIncremental models need to reconcile the existing target table with newly staged rows. Because this always points to the model's final Relation, it is safe to use as the target of MERGE/DELETE/INSERT.
Major adapters such as BigQuery, Snowflake, and Databricks all handle quoting and full qualification of {{ this }} correctly. Dialect differences show up in WHEN clauses and IDENTIFIER quoting, but the role of this itself is uniform.
Standard MERGE pattern for incremental models
-- models/fct_orders.sql
{{ config(materialized='incremental', unique_key='order_id', on_schema_change='sync_all_columns') }}
with staged as (
select * from {{ ref('stg_orders') }}
)
{% if is_incremental() %}
merge into {{ this }} as t
using staged as s
on t.order_id = s.order_id
when matched then update set
updated_at = s.updated_at,
total_amount = s.total_amount
when not matched then insert (order_id, updated_at, total_amount)
values (s.order_id, s.updated_at, s.total_amount)
{% else %}
select * from staged
{% endif %}Inside a generic test, these two are often confused. this refers to the test itself (the temporary test relation dbt generates), while model refers to the tested model (the Relation resolved via ref).
When you write a custom column test, keeping the split clear — read from model, write the aggregated output to this — avoids most of the confusion.
Safe pattern for a generic test (not-null example)
-- tests/generic/not_null.sql (example)
-- args: model, column_name
with src as (
select * from {{ model }}
)
select
count_if({{ column_name }} is null) as null_cnt
from src
-- this is the test node (output destination). Aggregate results are stored here.pre-hooks and post-hooks (on models, snapshots, and seeds) can use this. A common pattern is to run GRANT statements or statistics updates against this in a post-hook.
Avoid using this inside ephemeral models since they do not create a physical object. Ephemerals are inlined into downstream models and are not tied to an explicit Relation.
GRANT in a post-hook (Snowflake example)
-- models/dim_customers.sql
{{ config(
materialized='table',
post_hook=[
"grant select on {{ this }} to role ANALYST"
]
) }}
select * from {{ ref('stg_customers') }}When you invoke a macro standalone via dbt run-operation, there is no current node context and this is undefined. To work with a Relation, accept database/schema/identifier as arguments and resolve via adapter.get_relation.
this is available when a macro is called from a model, but to make a macro reusable and general-purpose, it is safer to accept the Relation as an explicit argument.
For run-operation: handle the Relation via explicit arguments
-- macros/admin.sql
{% macro drop_if_exists(database, schema, identifier) %}
{% set rel = adapter.get_relation(database=database, schema=schema, identifier=identifier) %}
{% if rel is not none %}
{{ adapter.drop_relation(rel) }}
{% else %}
{{ log('relation not found: ' ~ database ~ '.' ~ schema ~ '.' ~ identifier, info=True) }}
{% endif %}
{% endmacro %}
-- Example: dbt run-operation drop_if_exists --args '{"database": "ANALYTICS", "schema": "CORE", "identifier": "OLD_TABLE"}'On the Analytics Engineer exam, the roles of ref/source/this, the right place to use this in incremental models, and the difference between this and model in generic tests are all frequent topics.
Lock in the basics — "this is always the current node," "ref resolves dependencies and forms the DAG," "source explicitly marks external systems" — and be ready to explain how this can be undefined in hook and macro contexts.
Attribute-inspection snippet (for study)
-- models/_debug_this.sql (handy for learning)
select
'{{ this }}' as relation,
'{{ this.database if this is not none else "" }}' as db,
'{{ this.schema if this is not none else "" }}' as sch,
'{{ this.identifier if this is not none else "" }}' as idAnalytics Engineer
問題 1
When running an incremental model and you want to safely MERGE against the existing table, which use of a dbt built-in variable is most appropriate?
正解: A
For incremental models, the correct answer is putting {{ this }} — which points to your own existing Relation — as the MERGE target. ref and source point to different resources, and target is not a Relation, so neither fits. Hand-built string concatenation bypasses the adapter's quoting and full-qualification logic and is unsafe.
Which file types support this?
It is available in models, snapshots, test SQL, and hooks (pre/post). It is not available in seed CSV files themselves, but it does work inside hooks attached to seeds. Macros invoked standalone via run-operation do not have this defined.
Does this behave differently across adapters like BigQuery or Snowflake?
The meaning of this (the Relation of the current node) is consistent across adapters, and each adapter handles fully qualified naming and quoting appropriately at render time. BigQuery uses project.dataset.table and Snowflake uses database.schema.identifier, but you can use {{ this }} as-is in either case.
Can I reference the tested data by using this in a generic test?
No. In a generic test, this refers to the test node (where results are written), while the tested model is referenced via model. Use {{ model }} to read the data being tested.
Practice with certification-focused question sets
無料で問題を解いてみる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.
dbt Models: SQL-Defined Transformation Units (2026)
Model fundamentals — SELECT-based definitions, naming, refs,...
dbt Analytics Engineering Exam: Complete Guide (2026)
Pass the AE Certification — scope, weighting, sample questio...
dbt Cloud vs dbt Core: Feature & Cost Comparison (2026)
Honest comparison of dbt Cloud vs. dbt Core — IDE, scheduler...
dbt Project Structure: models/seeds/macros Layout (2026)
Recommended dbt project layout — models, seeds, macros, snap...
dbt_project.yml Explained: Every Config (2026)
Every dbt_project.yml setting that matters — paths, vars, ma...