Peter Hennings
03/13/2026, 9:00 PMMarvin
03/13/2026, 9:00 PMMarvin
03/13/2026, 9:03 PMfrom prefect import flow
from prefect.runner.storage import GitRepository
@flow
def my_flow():
...
# Dev
flow.from_source(
source=GitRepository(url="<https://github.com/org/repo.git>", branch="dev"),
entrypoint="flows.py:my_flow",
).deploy(name="my-flow-dev", work_pool_name="my-pool")
# Prod (optionally pin to a commit for reproducibility)
flow.from_source(
source=GitRepository(url="<https://github.com/org/repo.git>", branch="main"),
entrypoint="flows.py:my_flow",
).deploy(name="my-flow-prod", work_pool_name="my-pool")
If you want to avoid duplication in code, use CI/CD to update each deployment with the correct branch. You can template the branch in prefect.yaml with env vars or Prefect variables, but that’s evaluated when you create/update the deployment—not at run time—so it still results in separate deployment definitions.
If helpful, I can sketch a minimal prefect.yaml or CI job that updates both deployments cleanly.Peter Hennings
03/13/2026, 9:12 PMMarvin
03/13/2026, 9:12 PMMarvin
03/13/2026, 9:15 PMPeter Hennings
03/13/2026, 9:25 PMMarvin
03/13/2026, 9:25 PMMarvin
03/13/2026, 9:27 PMpull:
- my_steps.choose_branch:
id: pick
default: main
- prefect.deployments.steps.git_clone:
repository: <https://github.com/org/repo.git>
branch: "{{ pick.branch }}"
credentials: "{{ prefect.blocks.github-credentials.my-token }}"
- prefect.deployments.steps.set_working_directory:
directory: repo
deployments:
- name: my-single-deployment
entrypoint: flows.py:my_flow
work_pool:
name: my-pool
# Optionally define job_variables with env to drive the branch at runtime
job_variables:
env:
GIT_BRANCH: main
my_steps.py
async def choose_branch(default="main") -> dict:
import os
branch = os.getenv("GIT_BRANCH", default)
# Optional: allow a Prefect Variable to override
try:
from prefect.client.orchestration import get_client
client = await get_client()
var = await client.read_variable_by_name(name="branch_override")
if var and getattr(var, "value", None):
branch = var.value
except Exception:
# Don’t fail the pull pipeline if variables aren’t available
pass
return {"branch": branch}
Ways to drive the branch per run:
- Set an environment variable per run (e.g., via job_variables on the deployment/work pool, or via your run-creation automation).
- Flip a Prefect Variable (e.g., branch_override) without redeploying.
Other workable approaches if you don’t want Git:
- Remote storage artifact selection: publish per-branch bundles (S3/GCS/Azure) and use a custom step (or step output chaining) to pick the path/key at run time before pull_from_remote_storage.
- Container image selection: build images per branch and choose the image tag via job_variables. This selects code at runtime indirectly, if your process can override job variables on run submission.
Trade-offs to be aware of:
- Reproducibility: a single deployment that dynamically pulls branches makes “what code ran?” depend on external state (env var/variable), so pinning exact versions per run is harder.
- Governance: multiple deployments remain the clearest, most auditable path for prod vs. test.
If you share your worker type (Kubernetes/Docker/process), how you launch runs (UI, API, CI), and where you’d prefer to set the branch (env var, Prefect Variable, etc.), I can tailor a minimal working example for your setup.