In Prefect, how do a deployment's job variables relate to the work pool's base job template?
answer
- the pool ships defaults, the deployment ships exceptions
- a merge, not a replacement
- three layers, last write wins per key
- they configure the container, not the function
- not the same thing as parameters
basics
~20 sA Prefect work pool's base job template declares the infrastructure settings available to its runs and their defaults; a deployment's job_variables override those defaults for that deployment only, and an individual run can override them again at trigger time.
solid answer
~40 sEach work pool carries a **base job template**: a JSON-schema document exposing variables such as `image`, `env`, `cpu`, `memory`, `namespace` or `service_account_name`, with pool-wide defaults, plus the job configuration those variables are interpolated into. A deployment assigned to that pool inherits every default. Setting `job_variables` on the deployment — in `prefect.yaml` under `work_pool`, or as `job_variables={...}` in `flow.deploy()` — overrides just the keys you name; everything else still comes from the pool. A specific flow run can override again when triggered from the UI or CLI. So precedence is pool default → deployment job variables → per-run override, last one winning per key. This is how one Kubernetes pool serves many deployments that need different images, memory limits or environment variables without a pool per flow.
code
yaml · 12 linesdeployments:
- name: heavy-nightly
entrypoint: flows/etl.py:etl_flow
parameters:
day: "yesterday" # arguments to the flow function
work_pool:
name: k8s-prod
job_variables: # infrastructure overrides only
image: acme/pipelines:v2026.08.20
memory: "8Gi"
env:
LOG_LEVEL: INFOgo deeper
Recognize that a deployment can override infrastructure settings like the image or memory for itself, and that these are separate from the parameters passed to your flow function.
Explain the merge order — pool template defaults, then deployment job_variables, then per-run overrides — and that only variables the template exposes can be set.
Show how you use this in practice: one pool per environment with organizational defaults, images pinned per deployment to a CI-built tag, and one-off memory bumps done as run overrides rather than redeploys.
Own the split between platform-controlled defaults and team-controlled overrides, including who may edit base job templates, how those edits are reviewed, and how secrets stay out of stored job variables.
## Three layers, one merge Infrastructure configuration in Prefect is layered, and job variables are the middle layer. 1. **Base job template (pool)** — attached to the work pool. It has two parts: a `variables` block, which is a JSON schema naming the knobs (`image`, `env`, `cpu`, `memory`, `namespace`, `service_account_name`, `finished_job_ttl`, and so on) with types and defaults; and a `job_configuration` block, the actual infrastructure payload (for a Kubernetes pool, a Job manifest) with `{{ variable }}` placeholders the variables fill in. 2. **Job variables (deployment)** — a dict of overrides stored on the deployment. Keys must be variables the pool's template exposes. 3. **Per-run overrides** — when you trigger a run manually from the UI or CLI you can override job variables again for that run only, which is the standard trick for a one-off "run it with double the memory". At run time the worker merges these — pool defaults first, then deployment job variables, then run overrides — and renders the job configuration from the result. ## What it looks like ```yaml deployments: - name: heavy-nightly entrypoint: flows/etl.py:etl_flow work_pool: name: k8s-prod work_queue_name: batch job_variables: image: acme/pipelines:v2026.08.20 memory: "8Gi" env: LOG_LEVEL: INFO ``` or equivalently: ```python flow.deploy( name="heavy-nightly", work_pool_name="k8s-prod", job_variables={"image": "acme/pipelines:v2026.08.20", "memory": "8Gi"}, ) ``` Everything not mentioned — namespace, service account, image pull policy, the shape of the Job manifest itself — still comes from the pool. ## Why this layering is the point of work pools Without it you would need a work pool per resource profile, and a worker per pool. With it, a platform team owns one `k8s-prod` pool that encodes the organizational defaults — the right namespace, the right service account, log settings, a sane default image and TTL — and pipeline teams override only the two or three keys their flow actually needs. The template is the policy surface; job variables are the exception surface. It also gives you promotion for free: the same flow deployed twice, to `dev` and `prod` pools or with different job variables, differs by a dict rather than by a fork of the infrastructure definition. Pointing the image job variable at a CI-computed tag is the usual way a deployment gets pinned to a build. ## Boundaries and gotchas - **Job variables are infrastructure, not parameters.** `parameters` are arguments passed to your flow function and are validated against its type annotations. `job_variables` never reach your Python code as arguments; they shape the container or process the code runs in. Mixing them up is the single most common confusion here. - **You can only set what the template exposes.** If a pool's template has no `memory` variable, setting `memory` does nothing useful. Extending the knob set means editing the base job template (advanced infrastructure customization), which is a pool-level, platform-team change. - **Changing a pool default is retroactive.** It affects every deployment on the pool that has not overridden that key, on the next run. That is either a convenient fleet-wide change (bump the default image) or an unannounced one — treat the base job template as reviewed configuration. - **`env` merging** is a frequent source of surprise: what you set at the deployment layer replaces the value for that key rather than appending to a list of unrelated settings, so keep environment defaults in the template deliberately. - **Values are visible in the API.** Job variables are stored on the deployment and shown in the UI, so credentials belong in blocks or a secret store referenced by the infrastructure, not pasted into `env`. ## Version note This describes Prefect 3.x. In Prefect 2's original model, infrastructure was configured by attaching an **infrastructure block** (`KubernetesJob`, `DockerContainer`, `Process`) to the deployment and using `infra_overrides`; work pools with base job templates and `job_variables` replaced that.
- How do Prefect job variables differ from a deployment's parameters?Parameters are arguments to your flow function, validated against its annotations and visible inside your code. Job variables configure the infrastructure the code runs in — image, memory, env, namespace — and never appear as function arguments. A run can override either, but they are separate fields with separate audiences: pipeline logic versus runtime environment.
- A pool's base job template has no memory variable. How do you give one deployment more memory?You cannot do it from the deployment alone — job variables can only set keys the template exposes. Someone with pool access edits the base job template to surface `memory` (mapping it into the Job manifest's resource requests), after which any deployment on the pool can override it. That edit is deliberately a platform-level change.
- What happens to existing deployments when you change a default in the work pool's base job template?On their next run they pick up the new default, unless they override that key in job variables. That makes template edits a fleet-wide change — great for bumping a base image or a TTL, dangerous if unreviewed. Treat the template as versioned configuration and announce changes like any shared-infrastructure edit.
The base job template is the rental company's standard vehicle spec; job variables are the boxes you tick on your booking — same fleet, your engine size and your extras.
saying these in an interview costs you the question
- Confuses job variables with flow parameters passed to the function
- Thinks job variables replace the whole base job template rather than merging
- Believes any key can be overridden regardless of the template's schema
- Assumes a change to the pool's defaults only affects new deployments
- Puts credentials directly in job variable env values