Build your Git-based dbt project against the Contrast Warehouse, on a Contrast schedule or your own runner.
Keep your dbt project and Git repository. The dbt-contrast adapter
sends SQL to Contrast's public API. Contrast runs the queries and manages storage
and catalog updates. You do not need AWS credentials or physical catalog names.
Install the adapter from PyPI. Access to the private product repository is not required.
dbt_project.yml are filled in; change them,
or the models to run (a dbt selector such as +orders or tag:daily), under
More options. Add the pipeline.The same Pipelines page provides run history, model and test graphs, logs, failure alerts, pause, resume and ownership transfer. Each occurrence resolves the branch to an immutable commit; retries reuse that commit. Runs use the chosen key's workspace and database permissions, without AWS credentials in dbt. Revoking or expiring the key stops further runs.
Before building, each run runs dbt source freshness for the sources the
selected models read that declare freshness (with a loaded_at_field). A
source past error_after stops the run before anything is built, and the run's
error names the source, its age and the limit. A source past warn_after, or one
whose freshness could not be checked, adds a warning to the run's log and the
build continues. Sources without freshness are not checked.
Hosted projects use the standard dbt resource folders and SQL models and tests. Custom macros, packages, Python models, hooks and destination overrides are not supported by this hosted runner. Use your own runner for projects needing those features. A failed build or test may leave models already built updated; dbt does not make the whole project atomic.
Use dbt Core 1.11 and Python 3.12 for the quickstart. The adapter supports Python 3.10 through 3.13. dbt Cloud and Fusion are not supported by this release.
Supported operations include Iceberg SQL tables, ephemeral models, CSV seeds,
data tests, docs generation, and incremental append and merge. Existing
ref, source, Jinja, and packages still work subject to supported SQL and adapter
macros. SQL or macros specific to another warehouse may need changes.
Persisted models must use materialized='table' or materialized='incremental'.
Views are unsupported. Use ephemeral for models compiled into their consumers.
If you already have Athena views, convert or relocate them through their original
engine before reusing their names or refreshing the warehouse catalog.
Create your Contrast Warehouse and output databases first, for example
analytics_dev and analytics_prod. Writes use the default schema; dbt does
not provision databases or custom output schemas.
Each successful build records lineage from the tables a model reads to the table
it writes. To see it, ask an agent connected to the Contrast MCP for a
table's upstream or downstream tables (catalog action lineage).
dbt signs in with an API key. A workspace owner or admin creates one in MCP → API access.
DBT_ENV_SECRET_CONTRAST_TOKEN, and the workspace ID as
CONTRAST_WORKSPACE_ID. Never commit the key or print it in logs.write key in
MCP → API access, open Limit warehouse writes and list the databases it
may write to.API keys are on by default. If an admin turned them off, an owner or admin can turn them back on in Admin settings → Sign-in, or from Pipelines when choosing a key.
Install into your project's virtual environment:
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install 'dbt-contrast==0.1.0'Keep your existing dependency lock process for reproducible production installs.
Set profile: contrast in your existing dbt_project.yml, then save this
secret-free profile as .dbt/profiles.yml in the project:
contrast:
target: dev
outputs:
dev: &contrast
type: contrast
endpoint: https://api.embrasure.ai
workspace_id: "{{ env_var('CONTRAST_WORKSPACE_ID') }}"
token: "{{ env_var('DBT_ENV_SECRET_CONTRAST_TOKEN') }}"
database: analytics_dev
schema: default
threads: 4
query_timeout: 1800
prod:
<<: *contrast
database: analytics_prodInject the two environment variables through your secret manager, then run:
dbt deps
dbt debug --profiles-dir .dbt --target dev
dbt build --profiles-dir .dbt --target dev
dbt docs generate --profiles-dir .dbt --target devUse logical names from Contrast's catalog for sources:
version: 2
sources:
- name: crm
database: raw
schema: salesforce
tables:
- name: account{{ source('crm', 'account') }} reads raw.salesforce.account. A model named
accounts writes analytics_dev.default.accounts in dev and
analytics_prod.default.accounts in prod. Ingestion destinations and outputs
owned by managed Contrast pipelines cannot be overwritten by external dbt.
In your dbt repository, create a GitHub environment called dbt-production.
Add the token as an environment secret named DBT_ENV_SECRET_CONTRAST_TOKEN
and the workspace UUID as an environment variable named CONTRAST_WORKSPACE_ID.
Restrict that environment to your trusted main branch. Required environment
reviewers will make scheduled jobs wait for approval, so choose that policy deliberately.
With your dbt project at the repository root, save this as
.github/workflows/dbt.yml. Adjust the branch, cron, and paths for your project.
name: Build Contrast models
on:
workflow_dispatch:
schedule:
- cron: '17 6 * * *' # Daily at 06:17 UTC; GitHub may delay scheduled jobs.
permissions:
contents: read
concurrency:
group: contrast-analytics-prod
cancel-in-progress: false
jobs:
dbt:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 60
environment: dbt-production
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- run: python -m pip install 'dbt-contrast==0.1.0'
- run: dbt deps
- name: Build production models
env:
CONTRAST_WORKSPACE_ID: ${{ vars.CONTRAST_WORKSPACE_ID }}
DBT_ENV_SECRET_CONTRAST_TOKEN: ${{ secrets.DBT_ENV_SECRET_CONTRAST_TOKEN }}
run: |
dbt debug --profiles-dir .dbt --target prod
dbt build --profiles-dir .dbt --target prodGitHub concurrency groups only coordinate jobs in the same repository. Use the same group for every workflow writing these outputs, and coordinate other repositories or schedulers separately. Do not run concurrent full builds against the same destination tables. This example does not run untrusted pull request code with production credentials or upload dbt artifacts automatically; compiled SQL and artifacts can contain sensitive information.
Your runner owns scheduling, Git checkout, job dependencies, overlap prevention, notifications, and retry decisions. Contrast owns each query's authorization, execution, limits, history, and catalog reconciliation.
dbt debug with the replacement and run a small
build in a separate dev database before the next production job.A 401 can mean an invalid, expired, or revoked token. A 403 can mean disabled
PATs, insufficient scope, or changed workspace membership. Check these before
retrying. Do not print the secret while diagnosing authentication failures.
append is the default; merge requires unique_key. Use
--full-refresh for schema changes. Automatic schema evolution and snapshots
are not supported.persist_docs, and multi-statement transactions are not supported. Hooks autocommit.query_timeout defaults to 1,800 seconds, with a server maximum of 3,600 per
query. The existing scan limit still applies. A job timeout is separate from
a query timeout; stopping a runner does not guarantee an immediate server cancellation.Use a dedicated dev database to verify an existing project before moving its production schedule to Contrast.