Hassan Hashmi
03/26/2026, 5:53 PMMarvin
03/26/2026, 5:53 PMMarvin
03/26/2026, 5:53 PMHassan Hashmi
03/26/2026, 5:54 PMMarvin
03/26/2026, 5:54 PMMarvin
03/26/2026, 6:02 PMpip install "prefect[dbt]" dbt-duckdb # or dbt-snowflake / dbt-bigquery / dbt-postgres, etc.
prefect block register -m prefect_dbt
- Log in to Cloud (Hobby) and select your workspace:
prefect cloud login --key <PREFECT_API_KEY> --workspace <account>/<workspace>
Step 2 — Add a flow that runs dbt (recommended: PrefectDbtRunner)
Create a small flow in your repo (e.g., flows/dbt_build.py). PrefectDbtRunner gives you node-level visibility and assets automatically.
from prefect import flow
from prefect_dbt import PrefectDbtRunner, PrefectDbtSettings
@flow(name="dbt-build")
def dbt_build():
settings = PrefectDbtSettings(
project_dir="./dbt_project", # path to your dbt project (contains dbt_project.yml)
profiles_dir="~/.dbt" # or point to a repo-local .dbt dir
)
runner = PrefectDbtRunner(settings=settings, raise_on_failure=True)
runner.invoke(["build"]) # you can pass ["run"], ["test"], etc.
if __name__ == "__main__":
dbt_build()
Notes:
- You can also rely on env vars: DBT_PROJECT_DIR, DBT_PROFILES_DIR, DBT_LOG_LEVEL — the runner picks them up.
- Selection/vars example: runner.invoke(["run", "--select", "tag:daily", "--vars", "{'run_date':'2026-03-01'}"])
Step 3 — Provide dbt credentials cleanly
Pick one (or mix) of these patterns:
- Existing profiles.yml: set profiles_dir or DBT_PROFILES_DIR and keep secrets via env vars (e.g., {{ env_var('SNOWFLAKE_PASSWORD') }}) loaded from Prefect Secret blocks.
- Prefect block templating inside profiles.yml (lets you reference Prefect blocks/variables):
- Example in docs: Prefect + dbt (profiles.yml templating with {{ prefect.blocks.* }} and {{ prefect.variables.* }}).
- Programmatic profiles with DbtCliProfile (handy for Snowflake/BigQuery). See examples in the dbt docs page above.
Step 4 — Choose a work pool
- Quickstart (local dev): Process pool + worker on your machine that has your repo and dbt deps.
- Production: Docker or Kubernetes pool so runs are isolated and reproducible (image includes Prefect, dbt, and your adapter).
Create a work pool:
# Process (quickstart)
prefect work-pool create my-process-pool --type process
# Or Docker (recommended for prod)
prefect work-pool create my-docker-pool --type docker
Step 5a — Quickstart deploy (process worker, no Docker)
This is the fastest way to see runs in Cloud.
Option A: Use prefect deploy + prefect.yaml
- Add a minimal prefect.yaml at repo root:
name: dbt-workflows
prefect-version: ">=3.0.0"
deployments:
- name: dbt-build-dev
entrypoint: flows/dbt_build.py:dbt_build
work_pool:
name: my-process-pool
- Deploy:
prefect deploy
- Start a worker on your dev machine:
prefect worker start -p my-process-pool
Option B: Deploy from source in code (useful with GitHub)
```
from prefect import flow
from prefect_dbt import PrefectDbtRunner, PrefectDbtSettings
@flowMarvin
03/26/2026, 6:02 PMStep 5b — Production deploy (Docker worker)
- Build an image that includes Prefect, dbt, and your adapter(s):
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
RUN pip install "prefect[dbt]" dbt-snowflake # pick your adapter(s)
COPY . /app
ENV DBT_PROFILES_DIR=/app/.dbt
CMD ["python", "flows/dbt_build.py"]
- Use a prefect.yaml with build/push steps (prefect-docker) and your deployment:
name: dbt-workflows
prefect-version: ">=3.0.0"
build:
- prefect_docker.deployments.steps.build_docker_image:
id: build-image
requires: prefect-docker>=0.7.1
image_name: your-registry/dbt-flows
tag: latest
dockerfile: Dockerfile
push:
- prefect_docker.deployments.steps.push_docker_image:
requires: prefect-docker>=0.7.1
image_name: "{{ build-image.image_name }}"
tag: "{{ build-image.tag }}"
deployments:
- name: dbt-build-prod
entrypoint: flows/dbt_build.py:dbt_build
work_pool:
name: my-docker-pool
job_variables:
image: "{{ build-image.image }}"
env:
DBT_PROJECT_DIR: /app/dbt_project
DBT_PROFILES_DIR: /app/.dbt
- Deploy and start a Docker worker:
prefect deploy -n dbt-build-prod
prefect worker start -p my-docker-pool
Step 6 — Run or schedule from Cloud
- In Prefect Cloud, find your deployment (Deployments page), click “Run” or add a schedule.
- View logs and per-dbt-node task states in the flow run UI. dbt models and seeds also show up as Prefect assets.
Recommended practices for dbt + Prefect
- Prefer PrefectDbtRunner over shelling out — it gives node-level tasks, better logs, and asset lineage.
- Keep secrets out of repo:
- Use Prefect Secret blocks and/or profiles.yml env vars.
- Or use profiles.yml templating with Prefect blocks/variables.
- For production, use Docker/K8s workers so your dbt adapter versions are pinned and repeatable.
- Use `prefect deploy` (3.x) or `flow.from_source(...).deploy(...)` — do not use removed 2.x commands like `Deployment.build_from_flow()` or `prefect deployment build`.
- If using CI, on Hobby you’ll use a user API key in your pipeline (no service accounts). Store it as a CI secret and set `PREFECT_API_KEY`/`PREFECT_API_URL` in your job.
- Tag your deployment (e.g., `env:dev`, `env:prod`) and mirror that in dbt selectors.
Common tweaks you might need
- Selecting a subset:
runner.invoke(["run", "--select", "tag:daily+"])
- Passing vars:
runner.invoke(["run", "--vars", "{'run_date':'2026-03-01'}"])
- Using env for dbt:
# set once in job env (Docker/K8s) or in your flow before invoking
DBT_PROJECT_DIR=/app/dbt_project
DBT_PROFILES_DIR=/app/.dbt
```
Useful links
- Prefect + dbt integration (installation, runner, profiles)
- Deployments (3.x)
- Work pools and workers
Questions to tailor next steps for you
- Which adapter are you using (e.g., DuckDB, Snowflake, BigQuery)?
- Do you prefer to start with a Process worker on your dev machine, or go straight to a Docker/K8s worker?
- Do you have a repo where we can deploy from Git (recommended), or do you want to deploy from your local working copy first?
If you share those details, I’ll give you a targeted snippet (profiles.yml templating or Dockerfile/job variables) for your exact setup.Hassan Hashmi
03/27/2026, 2:14 PMMarvin
03/27/2026, 2:14 PMMarvin
03/27/2026, 2:17 PM{{ env_var('...') }} keys if those environment variables are set at runtime.
- In your flow, load the GcpCredentials block, export its fields to the env vars your profiles.yml expects, then invoke dbt.
Example:
from prefect import flow
from prefect_dbt import PrefectDbtRunner, PrefectDbtSettings
from prefect_gcp import GcpCredentials
import os
def export_bq_env_from_block(block_name: str):
creds = GcpCredentials.load(block_name)
info = creds.service_account_info # dict of your service account JSON
# Map service account JSON fields to the env vars used in your profiles.yml
os.environ["DBT_BQ_PROJECT_ID"] = info["project_id"]
os.environ["DBT_BQ_PRIVATE_KEY_ID"] = info["private_key_id"]
os.environ["DBT_BQ_PRIVATE_KEY"] = info["private_key"]
os.environ["DBT_BQ_CLIENT_EMAIL"] = info["client_email"]
os.environ["DBT_BQ_CLIENT_ID"] = info["client_id"]
os.environ["DBT_BQ_AUTH_URI"] = info["auth_uri"]
os.environ["DBT_BQ_TOKEN_URI"] = info["token_uri"]
os.environ["DBT_BQ_AUTH_PROVIDER_X509_CERT_URL"] = info["auth_provider_x509_cert_url"]
os.environ["DBT_BQ_CLIENT_X509_CERT_URL"] = info["client_x509_cert_url"]
# Also set dataset/location (these are not in the SA JSON)
# Prefer pulling from Prefect Variables or your deployment env
# Example:
# os.environ["DBT_BQ_DEV_DATASET"] = "your_dataset"
# os.environ["DBT_BQ_LOCATION"] = "US"
@flow
def dbt_build():
export_bq_env_from_block("CREDENTIALS-BLOCK-NAME")
settings = PrefectDbtSettings(
project_dir="./dbt_project",
profiles_dir="~/.dbt" # or repo-local .dbt
)
PrefectDbtRunner(settings=settings, raise_on_failure=True).invoke(["build"])
if __name__ == "__main__":
dbt_build()
Notes:
- The private_key string from Google usually includes literal \n. You should pass it as-is to the env var; dbt/Google auth handles it correctly.
- In deployments (Docker/K8s), you can either:
- Run the same “export” code at runtime (as above), or
- Pre-set those env vars via job variables if you’re not loading a block at runtime. The block approach is usually simpler and safer.
B) Let Prefect generate profiles.yml from your GcpCredentials block (no env vars needed)
- Use the dbt CLI wrappers with a programmatic profile. This plugs your GcpCredentials block directly into dbt’s BigQuery profile, and Prefect writes a profiles.yml for the run.
Example:
from prefect import flow
from prefect_gcp import GcpCredentials
from prefect_dbt.cli.configs import BigQueryTargetConfigs
from prefect_dbt.cli.credentials import DbtCliProfile
from prefect_dbt.cli.commands import run_dbt_build
@flow
def dbt_build():
gcp = GcpCredentials.load("CREDENTIALS-BLOCK-NAME")
target = BigQueryTargetConfigs(
schema="your_dev_dataset", # BigQuery dataset
project="your-gcp-project", # or omit if set in the block
credentials=gcp,
# extras={"location": "US"} # optional: set region and other BQ options
)
profile = DbtCliProfile(
name="le_analytics_dbt",
target="dev",
target_configs=target,
)
# overwrite_profiles=True tells Prefect to write a profiles.yml for this run
run_dbt_build(
project_dir="./dbt_project",
dbt_cli_profile=profile,
overwrite_profiles=True,
create_summary_artifact=True
)
if __name__ == "__main__":
dbt_build()
When to pick which
- Use A (env vars + PrefectDbtRunner) if you want dbt node-level task visibility and asset lineage with the recommended runner, and you’re happy keeping your current profiles.yml shape. Just set env vars from the block before invoking.Marvin
03/27/2026, 2:17 PMrun_dbt_build, run_dbt_run, etc.).
A couple of extra tips
- Keep dataset and location outside of the service account JSON (as you already do). You can set them via env vars, Prefect Variables, or extras={"location": "US"} in BigQueryTargetConfigs.
- For production, prefer a Docker/K8s worker and bake dbt + adapters into the image. Then either:
- Load the GcpCredentials block at runtime (code above) and export env vars, or
- Use the DbtCliProfile path to avoid env vars entirely.
Reference: Prefect + dbt integration guide
If you tell me your preferred approach (Runner vs CLI tasks) and where your profiles.yml lives, I can tailor the snippet to your exact repo and deployment type.Hassan Hashmi
04/03/2026, 5:00 PMMarvin
04/03/2026, 5:00 PMMarvin
04/03/2026, 5:00 PMHassan Hashmi
04/03/2026, 5:01 PMMarvin
04/03/2026, 5:01 PMMarvin
04/03/2026, 5:04 PMflow.serve running 24/7 on Windows. Since serve() is a long‑running, blocking process, the trick is to run it as a background service that auto-starts and restarts on failure.
Here are reliable options:
1) Windows service with NSSM (recommended)
- Why: simple, robust auto-restart, runs without a user session.
- Steps:
- Install NSSM from nssm.cc.
- Create your flow file, e.g. `C:\flows\my_flow.py`:
from prefect import flow
@flow
def my_flow():
print("Hello from Windows!")
if __name__ == "__main__":
# interval schedule example
my_flow.serve(
name="windows-service-deployment",
interval=3600,
pause_on_shutdown=False # keeps schedule active across restarts
)
- Register a service (run an elevated PowerShell or CMD):
- Easiest via GUI:
- Run: nssm install PrefectServe
- Path: point to your Prefect CLI executable, e.g. C:\path\to\venv\Scripts\prefect.exe
- Arguments: flow serve C:\flows\my_flow.py:my_flow -n windows-service-deployment
- Startup directory: C:\flows
- (Optional) Set stdout/stderr log files on the “I/O” tab for logging.
- On “Environment” tab, add:
- PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<ACCOUNT-ID>/workspaces/<WORKSPACE-ID>>
- PREFECT_API_KEY=<YOUR-API-KEY>
- Save, then start: nssm start PrefectServe
- Or via command line:
nssm install PrefectServe "C:\path\to\venv\Scripts\prefect.exe" "flow serve C:\flows\my_flow.py:my_flow -n windows-service-deployment"
nssm set PrefectServe AppDirectory "C:\flows"
nssm set PrefectServe AppEnvironmentExtra "PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<ACCOUNT-ID>/workspaces/<WORKSPACE-ID>>"
nssm set PrefectServe AppEnvironmentExtra "PREFECT_API_KEY=<YOUR-API-KEY>"
nssm set PrefectServe AppRestartDelay 5000
nssm start PrefectServe
- Notes:
- Using the CLI (prefect flow serve ...) is equivalent to calling my_flow.serve() in your script.
- If you prefer to run the Python file directly, set the NSSM Path to C:\Python312\python.exe and Arguments to C:\flows\my_flow.py.
2) Windows Task Scheduler (built-in)
- Good if you don’t want third-party tools, but less robust for true “service”-style uptime.
- Create a small batch wrapper to set env and run your script:
@echo off
set PREFECT_API_URL=<https://api.prefect.cloud/api/accounts/<ACCOUNT-ID>/workspaces/<WORKSPACE-ID>>
set PREFECT_API_KEY=<YOUR-API-KEY>
set PYTHONIOENCODING=UTF-8
cd /d C:\flows
C:\Python312\python.exe C:\flows\my_flow.py
- In Task Scheduler:
- Create Task → Triggers: “At startup”
- General: “Run whether user is logged on or not”
- Action: “Start a program” → point to the batch file
- Settings: enable restart on failure, and “If the task is already running, do not start a new instance”
3) Docker (optional alternative)
- Run your flow in a container with restart: always. Useful if you already use Docker Desktop on Windows.
Important notes
- serve() is blocking: it must run as a dedicated, long‑running process/service.
- For Prefect Cloud, set PREFECT_API_URL and PREFECT_API_KEY in the service’s environment.
- If you stop the serve process, schedules pause by default. Use pause_on_shutdown=False to keep them active through restarts.
You can also use the CLI directly (verified):
prefect flow serve --help
prefect flow serve ".\my_flow.py:my_flow" --name "windows-service-deployment" --interval 3600
Docs you may find helpful
- Run flows in local processes (serve): Run flows in local processes
- Connect to Prefect Cloud: Connect to CloudMarvin
04/03/2026, 5:04 PM