[新機能]dbt Projects on SnowflakeのSQL Environment Variablesで開発者ごとのスキーマ切り替えを試してみた
さがらです。
dbt Projects on Snowflakeの新機能として、SQL Environment Variablesがリリースされています。env.ymlというプロジェクト直下のファイルに環境ごとの変数を定義しておき、そこにCURRENT_USER()などのSQLを埋め込んで評価させることができる機能です。
以前このブログで、Workspaceの--varsフラグを使ってユーザーごとの開発用スキーマを動的に指定する方法を紹介しました。
この方法は動くものの、--vars '{"dev_schema": "dbt_ssagara"}'をユーザーごとにWorkspaceの実行コマンド欄へ手動で設定する必要があり、コマンドやRun/Buildの種類ごとに設定し直す手間がありました。今回のSQL Environment Variablesを使うと、env.yml側でCURRENT_USER()を評価してスキーマ名を組み立てられるため、この--varsの設定自体が不要になるのではと考え、実際に試してみました。
機能概要
env.ymlは、dbt Projects on Snowflakeのプロジェクトルート(dbt_project.ymlと同じ階層)に配置する、Git管理可能な設定ファイルです。環境ごとに名前付きの設定(environments)を定義でき、各環境のenv:セクションには、プレーンテキストの値だけでなく、1行・1列のVARCHARを返すSQLを指定できます。
env_config:
default_environment: dev
environments:
- name: dev
env:
DBT_TARGET_SCHEMA: "{{ select 'DBT_DEV_' || UPPER(CURRENT_USER()) }}"
ポイントは評価されるタイミングです。dbtプロジェクトを実行すると、Snowflakeが先にenv.ymlを解決して環境変数として実行コンテキストに注入し、そのあとでdbt Core本体が起動します。つまりCURRENT_USER()は、dbtが動く前のWorkspaceでの実行ユーザー・ロールという外側の実行コンテキストを使って評価されます。env.yml側で決定した値は、dbtのprofiles.ymlからenv_var('DBT_TARGET_SCHEMA')のように参照します。
schema: "{{ env_var('DBT_TARGET_SCHEMA') }}"
これまでvar('dev_schema')として--vars経由で渡していた値を、env.yml側で完結させられるようになった、というのが今回のアップデートの嬉しいポイントです。
制限事項
env.ymlには2MBのサイズ制限(おおよそ12,000行相当)がありますenv:内のキー名はすべてDBT_から始まる大文字である必要があります。またキー名(左辺)はプレーンテキストのみで、SQLは使えませんenv:の値に書けるJinjaは{{ select ... }}のパターンのみで、ループ・条件分岐・フィルタなどは使えません。またref()・source()などのマクロはenv.yml内のどこでも禁止されています- CI/CDワークフローで
--env-file-dirなどのフラグを使う場合は、Snowflake CLI 3.21以降が必要です - 環境変数の値の優先度は「
--env-varsなど実行時指定 > シェル環境変数(--use-shell-env-vars使用時のみ) >env.ymlの値」の順です
事前準備
1. Snowflakeオブジェクトの準備
検証用に、以下のオブジェクトを使用します。既存のものがあれば適宜読み替えてください。
| 種別 | 名前 |
|---|---|
| ウェアハウス | DBT_ENVVAR_DEMO_WH |
| データベース | DBT_ENVVAR_DEMO_DB |
| 開発者用ロール | DBT_ENVVAR_DEV_ROLE |
| 事前作成する出力先スキーマ | DBT_DEV_SAGARA_SATOSHI |
| 実行ユーザー | SAGARA_SATOSHI |
ACCOUNTADMINで、ウェアハウス・データベース・ロールを作成します。
USE ROLE ACCOUNTADMIN;
CREATE OR REPLACE WAREHOUSE DBT_ENVVAR_DEMO_WH
WAREHOUSE_SIZE = XSMALL
AUTO_SUSPEND = 60
AUTO_RESUME = TRUE;
CREATE OR REPLACE DATABASE DBT_ENVVAR_DEMO_DB;
CREATE OR REPLACE ROLE DBT_ENVVAR_DEV_ROLE;
ロールにウェアハウスとデータベースの利用権限を付与します。
GRANT USAGE ON WAREHOUSE DBT_ENVVAR_DEMO_WH
TO ROLE DBT_ENVVAR_DEV_ROLE;
GRANT USAGE ON DATABASE DBT_ENVVAR_DEMO_DB
TO ROLE DBT_ENVVAR_DEV_ROLE;
出力先スキーマも作成しておきます。
CREATE SCHEMA IF NOT EXISTS DBT_ENVVAR_DEMO_DB.DBT_DEV_SAGARA_SATOSHI;
GRANT USAGE ON SCHEMA DBT_ENVVAR_DEMO_DB.DBT_DEV_SAGARA_SATOSHI
TO ROLE DBT_ENVVAR_DEV_ROLE;
GRANT CREATE TABLE ON SCHEMA DBT_ENVVAR_DEMO_DB.DBT_DEV_SAGARA_SATOSHI
TO ROLE DBT_ENVVAR_DEV_ROLE;
最後に検証ユーザーSAGARA_SATOSHIへロールを付与します。
GRANT ROLE DBT_ENVVAR_DEV_ROLE TO USER SAGARA_SATOSHI;
2. dbtプロジェクトへのenv.yml追加
Workspace上で適当にdbtプロジェクトを作成します。

dbt_project.ymlと同じプロジェクトルートにenv.ymlを追加します。プロジェクト構成のイメージは以下の通りです。
your_dbt_project/
├── dbt_project.yml
├── env.yml
├── models/
│ └── envvar_schema_probe.sql
└── profiles.yml
env.ymlの中身です。
env_config:
default_environment: dev
environments:
- name: dev
env:
DBT_TARGET_SCHEMA: "{{ select 'DBT_DEV_' || UPPER(CURRENT_USER()) }}"
SAGARA_SATOSHIで実行した場合、CURRENT_USER()の評価結果を使って、環境変数DBT_TARGET_SCHEMAは次の値になる想定です。
DBT_DEV_SAGARA_SATOSHI
3. profiles.ymlのスキーマ設定を変更
以前の記事でvar('dev_schema')を参照していた箇所を、env_var('DBT_TARGET_SCHEMA')に変更します。
<プロジェクト名>:
target: dev
outputs:
dev:
type: snowflake
account: ""
user: ""
role: DBT_ENVVAR_DEV_ROLE
warehouse: DBT_ENVVAR_DEMO_WH
database: DBT_ENVVAR_DEMO_DB
schema: "{{ env_var('DBT_TARGET_SCHEMA') }}"
threads: 8
変更前後の差分はこちらです。
# 変更前:--vars で渡す値を参照
schema: "{{ var('dev_schema') }}"
# 変更後:env.yml で解決した環境変数を参照
schema: "{{ env_var('DBT_TARGET_SCHEMA') }}"
4. 動作確認用モデルの作成
環境変数、dbtが解決したtarget.schema、Snowflakeの実行ユーザーを1テーブルで確認できるモデルを作成します。
models/envvar_schema_probe.sql
{{ config(materialized='table') }}
SELECT
'{{ env_var("DBT_TARGET_SCHEMA") }}' AS env_target_schema,
'{{ target.schema }}' AS dbt_target_schema,
CURRENT_USER() AS session_user,
CURRENT_ROLE() AS session_role,
CURRENT_TIMESTAMP() AS built_at
このモデルで確認したい列は以下の通りです。
| 列 | 確認内容 |
|---|---|
ENV_TARGET_SCHEMA |
env.ymlから注入されたスキーマ名 |
DBT_TARGET_SCHEMA |
dbtのtargetとして解決されたスキーマ名 |
SESSION_USER |
モデル実行時のSnowflakeユーザー |
SESSION_ROLE |
モデル実行時のロール |
BUILT_AT |
モデルの実行時刻 |
試してみた
1. Workspaceからdbtを実行する(--varsは指定しない)
Runパネルで以下を設定します。ポイントは、以前私が書いた記事とは異なりAdditional flagsを一切設定しないことです。

実行してエラーが出なければOKです。

2. 実行結果を確認する
実行が成功すると、以下のようにユーザー名をスキーマに入れたスキーマにテーブルが出力されているはずです。

Snowflake上で結果を確認します。想定通りの結果が得られています。
USE ROLE DBT_ENVVAR_DEV_ROLE;
SELECT *
FROM DBT_ENVVAR_DEMO_DB.DBT_DEV_SAGARA_SATOSHI.ENVVAR_SCHEMA_PROBE;

お片付け
検証で作成したオブジェクトが不要な場合は、ACCOUNTADMINで以下を実行して削除します。
USE ROLE ACCOUNTADMIN;
DROP DATABASE IF EXISTS DBT_ENVVAR_DEMO_DB;
DROP WAREHOUSE IF EXISTS DBT_ENVVAR_DEMO_WH;
DROP ROLE IF EXISTS DBT_ENVVAR_DEV_ROLE;
気になったこと
今回検証を行なう中で特につまづくことはなかったのですが、1つ気になったことがあります。
それは、今回環境変数を定義しているvars.ymlはdbt Core 1.12からの新機能という理解なのですが、今回の検証ではRun実行時のdbtのバージョンが1.9.4でも問題なく実行できたことです。
これはなぜなのでしょう…気になるところです。

最後に
dbt Projects on SnowflakeのSQL Environment Variablesを使って、開発者ごとの出力先スキーマ切り替えを--varsなしで実現できるか試してみました。
CURRENT_USER()をenv.yml側で評価し、profiles.ymlのenv_var()から参照するだけで、以前の記事で紹介した「ユーザーごとに--varsをWorkspaceへ手動設定する」運用が不要になることを確認できました。開発者が増えるほど--varsの設定漏れは起きやすくなるので、Git管理されたenv.ymlにロジックを寄せられるのは嬉しいポイントだと感じました。
dbtで開発ユーザーごとにスキーマを用意する運用をする方は多いと思いますので、ぜひご活用ください!








