Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:MaterializeInc Materialize Deploy Promote Pattern

From Leeroopedia
Revision as of 15:38, 16 February 2026 by Admin (talk | contribs) (Auto-imported from implementations/MaterializeInc_Materialize_Deploy_Promote_Pattern.md)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)


Knowledge Sources misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_init.sql, misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_promote.sql, misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_cleanup.sql, misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_await.sql, misc/dbt-materialize/tests/adapter/test_deploy.py
Domains Deployment Strategy, Zero-Downtime Releases, Database Schema Management
Last Updated 2026-02-08

Overview

Pattern documentation for the blue-green deployment workflow in dbt-materialize, covering the deploy_init, deploy_await, deploy_promote, and deploy_cleanup macros that orchestrate zero-downtime deployments using ALTER SCHEMA SWAP and ALTER CLUSTER SWAP.

Description

The dbt-materialize blue-green deployment pattern is implemented as a set of four coordinated dbt macros, invoked via dbt run-operation. Together they provide a complete lifecycle for zero-downtime schema and cluster deployments.

deploy_init(ignore_existing_objects=False) -- Prepares the deployment environment:

  1. Reads the deployment variable from dbt_project.yml to get the list of clusters and schemas for the current target.
  2. Validates that all production schemas and clusters exist and do not contain sinks.
  3. Validates permissions via deploy_validate_permissions.
  4. For each schema, creates {schema}_dbt_deploy (or validates it if it already exists). Copies grants and default privileges from the production schema.
  5. For each cluster, reads the production cluster's configuration (size, replication factor, schedule type, hydration time estimate) and creates {cluster}_dbt_deploy with identical settings. Copies cluster grants.

deploy_await(poll_interval=15, lag_threshold='1s') -- Waits for hydration:

  1. For each deployment cluster, calls await_cluster_ready which polls the cluster's replication lag at poll_interval second intervals.
  2. Blocks until all objects in all deployment clusters are within the lag_threshold.

deploy_promote(wait=False, poll_interval=15, lag_threshold='1s', dry_run=False) -- Atomically promotes the deployment:

  1. Validates that all production and deployment schemas and clusters exist.
  2. Optionally calls deploy_await if wait=True.
  3. In a single BEGIN/COMMIT transaction, executes:
    • ALTER SCHEMA "public" SWAP WITH "public_dbt_deploy" for each schema pair.
    • ALTER CLUSTER "prod" SWAP WITH "prod_dbt_deploy" for each cluster pair.
  4. After the swap, discovers sinks whose upstream objects were in swapped schemas and runs ALTER SINK ... SET FROM ... to update their references.
  5. Tags deployed schemas with a comment including the deploying user, timestamp, and git commit SHA.
  6. In dry_run mode, logs the commands without executing them.

deploy_cleanup() -- Tears down the old deployment environment:

  1. Drops all {schema}_dbt_deploy schemas with CASCADE.
  2. Drops all {cluster}_dbt_deploy clusters with CASCADE.

Usage

Use this pattern when:

  • Deploying new or updated dbt models to Materialize production without downtime.
  • Setting up CI/CD pipelines for data model releases.
  • Needing to validate a deployment before promoting (using deploy_await and dry_run).
  • Managing grants and privileges across blue-green environments.

Code Reference

Source Location

File Description
misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_init.sql deploy_init macro (154 lines) -- environment preparation with grant copying
misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_await.sql deploy_await macro (48 lines) -- hydration polling
misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_promote.sql deploy_promote macro (235 lines) -- atomic swap, sink discovery, schema tagging
misc/dbt-materialize/dbt/include/materialize/macros/deploy/deploy_cleanup.sql deploy_cleanup macro (51 lines) -- environment teardown
misc/dbt-materialize/tests/adapter/test_deploy.py Integration tests: TestTargetDeploy (L407-500), TestEndToEndDeployment, TestLagTolerance

Signature

-- deploy_init: create deployment schemas and clusters
{% macro deploy_init(ignore_existing_objects=False) %}

-- deploy_await: poll for hydration readiness
{% macro deploy_await(poll_interval=15, lag_threshold='1s') %}

-- deploy_promote: atomically swap environments
{% macro deploy_promote(wait=False, poll_interval=15, lag_threshold='1s', dry_run=False) %}

-- deploy_cleanup: drop deployment environment
{% macro deploy_cleanup() %}

Import

These are dbt macros invoked via dbt run-operation, not Python imports. They require the deployment variable to be configured in dbt_project.yml.

# Required dbt_project.yml configuration
vars:
  deployment:
    default:
      clusters:
        - quickstart
      schemas:
        - public

I/O Contract

Inputs

Macro Parameter Type Description
deploy_init ignore_existing_objects bool When True, allows deployment schemas/clusters to contain pre-existing objects without raising an error. Default: False.
deploy_await poll_interval int Seconds between readiness checks. Default: 15.
deploy_await lag_threshold str Maximum acceptable replication lag (e.g., '1s', '5s', '1h'). Default: '1s'.
deploy_promote wait bool If True, calls deploy_await before promoting. Default: False.
deploy_promote dry_run bool If True, logs swap commands without executing them. Default: False.
deploy_promote poll_interval int Passed to deploy_await if wait=True. Default: 15.
deploy_promote lag_threshold str Passed to deploy_await if wait=True. Default: '1s'.

Outputs

Macro Output Description
deploy_init Side effects Creates deployment schemas and clusters, copies grants and default privileges.
deploy_await Blocks until ready No return value; execution halts until all deployment clusters are hydrated within the lag threshold.
deploy_promote Side effects Atomically swaps schemas and clusters, updates sinks, tags schemas with deployment metadata.
deploy_cleanup Side effects Drops deployment schemas and clusters with CASCADE.

Usage Examples

# Full deployment lifecycle

# 1. Initialize the deployment environment
dbt run-operation deploy_init \
  --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}}'

# 2. Build models in the deployment environment
dbt run --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}, deploy: True}'

# 3. Wait for hydration (optional, can be done separately)
dbt run-operation deploy_await \
  --args '{poll_interval: 10, lag_threshold: "5s"}' \
  --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}}'

# 4a. Dry run to validate (optional)
dbt run-operation deploy_promote \
  --args '{dry_run: true}' \
  --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}}'

# 4b. Promote (with optional wait)
dbt run-operation deploy_promote \
  --args '{wait: true}' \
  --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}}'

# 5. Clean up the old environment
dbt run-operation deploy_cleanup \
  --vars '{deployment: {default: {clusters: [quickstart], schemas: [public]}}}'
-- The atomic swap executed by deploy_promote (inside a transaction):
BEGIN;
ALTER SCHEMA "public" SWAP WITH "public_dbt_deploy";
ALTER SCHEMA "staging" SWAP WITH "staging_dbt_deploy";
ALTER CLUSTER "prod" SWAP WITH "prod_dbt_deploy";
COMMIT;

-- After swap, sinks are updated:
ALTER SINK "sinks_schema"."my_sink" SET FROM "materialize"."public"."my_view";
# Integration test pattern (from test_deploy.py TestTargetDeploy.test_dbt_deploy)
# Demonstrates ID swapping verification:

# Before promote: record IDs
before_clusters = dict(
    project.run_sql(
        "SELECT name, id FROM mz_clusters WHERE name IN ('prod', 'prod_dbt_deploy')",
        fetch="all",
    )
)

# Execute promotion
run_dbt(["run-operation", "deploy_promote"])

# After promote: verify IDs swapped
after_clusters = dict(
    project.run_sql(
        "SELECT name, id FROM mz_clusters WHERE name IN ('prod', 'prod_dbt_deploy')",
        fetch="all",
    )
)

# The ID that was under 'prod' is now under 'prod_dbt_deploy' and vice versa
assert before_clusters["prod"] == after_clusters["prod_dbt_deploy"]
assert before_clusters["prod_dbt_deploy"] == after_clusters["prod"]

Related Pages

Implements Principle

Requires Environment

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment