<@ULVA73B9P> in both ./.prefect/flows.json and ./p...
# ask-marvin
g
@Marvin in both ./.prefect/flows.json and ./prefect.yaml information on flows is stored. How do they relate to each other (prefect version 2.14.16) and the deployment of a flow via command-line?
m
thought for 592.6 seconds
Great question — and thanks for specifying Prefect 2.14.16. Short answer -
prefect.yaml
is the user-authored, source-of-truth project/deployment config used by
prefect deploy
(and by
prefect deployment build/apply
). -
.prefect/flows.json
is not a user-facing config. It’s an internal/cache file created by Prefect tooling to remember discovered flows in your repo (e.g., to speed up interactive selection). It is not read to register deployments and you generally shouldn’t edit it. It’s safe to delete; it will be regenerated. How they relate (and don’t) -
prefect.yaml
- Purpose: Defines your project’s deployments, including the flow entrypoints (
path/to/file.py:flow_func
), work pool/queue, parameters, schedules, and build/push/pull steps. - Used by:
prefect deploy
in Prefect 2.x reads this file to create/update deployments in the API. - Ownership: You edit and commit this file to version control. - Docs: https://docs-2.prefect.io/latest/guides/prefect-deploy/ -
.prefect/flows.json
- Purpose: A local cache Prefect creates to remember which flows it discovered in your codebase. This helps the CLI/tools quickly present available flows if you run commands interactively. - Used by: Only the local tooling for convenience. It is not authoritative for deployments and is not sent to the API. - Ownership: Not intended for manual edits, typically excluded from version control. Safe to delete; Prefect will recreate it. Deploying flows via the CLI in Prefect 2.14 - Config-driven (recommended when you have a
prefect.yaml
): - Define one or more deployments under the
deployments:
section in
prefect.yaml
with their
entrypoint
, work pool/queue, etc. - Then run from the project root:
Copy code
prefect deploy
- This reads
prefect.yaml
, runs any build/push steps, and registers the deployments. - Ad-hoc (single deployment without relying on
prefect.yaml
): - Build a deployment spec file:
Copy code
prefect deployment build ./path/to/file.py:flow_func -n my-deployment -q my-queue -p my-work-pool
- Then apply it:
Copy code
prefect deployment apply my-deployment.yaml
- This path is useful if you want a one-off deployment YAML you can review/commit. Key takeaways -
prefect.yaml
is authoritative and controls what gets deployed. -
.prefect/flows.json
is a local cache; it does not affect what’s deployed. - If you see both referencing flows, treat
prefect.yaml
as the truth. You can ignore or delete
.prefect/flows.json
if it ever looks stale. References - Prefect deploy guide (2.x): https://docs-2.prefect.io/latest/guides/prefect-deploy/ - Deployment concepts (2.x): https://docs-2.prefect.io/latest/concepts/deployments-block-based/ If you’re comfortable sharing, could you paste a small snippet of your
.prefect/flows.json
? I can confirm it matches the typical flow-discovery cache and point out anything unusual.
g
@Marvin so why do I specify the name entrypoint etc of the deployment in
prefect deploy path/to/file.py:flow_name
when it is entered beforehand in the .yaml (user authored)?
m
thought for 54.6 seconds
In Prefect 2.14.16 you don’t need to pass an entrypoint (or name, etc.) to
prefect deploy
if you’ve already declared the deployment(s) in
prefect.yaml
.
prefect deploy
will read the deployments from that file and register them. Why the CLI still accepts
ENTRYPOINT
and flags: - Two modes are supported: 1) Config-driven (from
prefect.yaml
): run from the project root and Prefect deploys the deployments you’ve defined. - Examples:
Copy code
prefect deploy
       prefect deploy -n 'my-flow/my-deployment'   # deploy just one by name pattern
2) Ad‑hoc (from CLI): pass
ENTRYPOINT
and flags to create/override a deployment on the fly, even if it isn’t in
prefect.yaml
. - Example:
Copy code
prefect deploy ./path/to/file.py:flow_func -n my-deployment -p my-pool -q my-queue
This is handy for quick experiments or when you don’t want to commit a
prefect.yaml
change. Precedence/merge behavior: - When you run
prefect deploy
with no entrypoint, Prefect uses the deployments declared in
prefect.yaml
. - CLI flags (like
--name
,
--work-pool
,
--param
, etc.) can override values defined in
prefect.yaml
for the deployments you select (e.g., with
-n
). - If you provide an
ENTRYPOINT
, Prefect can create a deployment from that entrypoint using the CLI options you pass, instead of (or in addition to) what’s in
prefect.yaml
. About `.prefect/flows.json`: - That file is just a local cache the tooling uses to remember discovered flows. It’s not authoritative for deployments and doesn’t need to match
prefect.yaml
. You don’t need to edit it; it’s safe to delete. Docs: - Prefect 2.x deploy guide: https://docs-2.prefect.io/latest/guides/prefect-deploy/ Recommendation: If you’ve already authored your deployments in
prefect.yaml
, just run
prefect deploy
(optionally with
-n
to select). Use the `ENTRYPOINT`/flags form for quick ad‑hoc runs or when you want to override without editing the YAML.
g
@Marvin So from locally testing to deploying our prefect pipelines via coolify, the best workflow would be to 1. start with a fresh repo with prefect installed and the .yaml empty. 2. enter the necessary flow configurations into the prefect .yaml 3. run prefect deploy 4. start the local server and test the flow runs 5. Since prefect.yaml is version controlled and copied into the container the commands for respective docker-deploy target in the Makefile can be simplified from the following
Copy code
# sends commands from outside into the pseudo-terminal of the container: deploying the specified prefect-flows
# docker ps lists running docker containers and filters for the given name and executes the prefect-deployment within that specific container
docker-deploy:
	# docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") prefect --no-prompt deploy src/mvp_test_flow.py:mvp_test_flow --pool goal100-work-pool --name mvp_test_flow
	docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") prefect --no-prompt deploy src/download_update_flow.py:download_update_flow --pool goal100-work-pool --name download_update_flow
docker: docker-build docker-run docker-deploy
to include only
docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") prefect --no-prompt deploy)
?
m
thought for 255.8 seconds
Short answer: yes, you can simplify the Makefile to a single
prefect deploy
call, but drop
--no-prompt
and make sure you either deploy “all” or explicitly select by name. A few notes to tighten up your workflow in Prefect 2.14.16: - If your
prefect.yaml
already contains the deployments (with
entrypoint
, work pool/queue, etc.), you do not need to pass entrypoints on the CLI. Just run
prefect deploy
from the project root. - In non‑interactive/CI contexts (like
docker exec
), avoid prompts by selecting deployments explicitly. Two safe options: - Deploy all from `prefect.yaml`:
Copy code
prefect deploy --all
- Deploy specific ones by name pattern:
Copy code
prefect deploy -n 'download_update_flow/*' -n 'mvp_test_flow/*'
In 2.14,
--no-prompt
is not a documented flag for
prefect deploy
, so don’t rely on it. - Ensure the command runs in the project root inside the container (where
prefect.yaml
lives) and that the container has
PREFECT_API_URL
set to your (local or Coolify) Prefect API. Given that, your Makefile can be simplified to one line, e.g.:
Copy code
docker-deploy:
	docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") bash -lc 'cd /app && prefect deploy --all'
- Replace
/app
with the project root path inside the container. - If you only want to deploy certain ones, swap
--all
for
-n
patterns:
Copy code
docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") bash -lc 'cd /app && prefect deploy -n "download_update_flow/*" -n "mvp_test_flow/*"'
Additional tips: - Make sure a worker is running and connected to the same work pool(s) you set in
prefect.yaml
so the deployments are picked up. - If your
prefect.yaml
has build/push steps, confirm they make sense inside the runtime container. If you’re already shipping the code in the image, keep
build:
and
push:
null so
prefect deploy
just registers deployments. Docs: https://docs-2.prefect.io/latest/guides/prefect-deploy/ If you want, paste your
prefect.yaml
deployments section and I’ll sanity‑check the
-n
patterns you’d use.
g
@Marvin interestingly, the prefect.yaml does not contain one flow, which appears in the ui. Neither on the deployed coolify-production-server version, nor in the local .yaml
m
thought for 110.5 seconds
A few likely explanations: - Deployments live in the API, not in your prefect.yaml. If you (or your Makefile) ever ran an ad‑hoc deploy like:
Copy code
prefect deploy ./src/some_file.py:some_flow --name some_deployment --pool some-pool
that creates a deployment directly in the API without touching prefect.yaml. It will keep showing up in the UI until deleted or overwritten, even if it isn’t in your YAML. - Or, you might just be seeing a Flow (under the Flows tab) rather than a Deployment. A Flow appears in the UI as soon as you run it once (even with
my_flow()
locally). That doesn’t require a deployment or an entry in prefect.yaml. Next steps to confirm and clean up: 1) List deployments:
Copy code
prefect deployments ls
Find the flow/deployment that “shouldn’t” be there. 2) Inspect it to see how it was created (entrypoint, storage, work pool, timestamps):
Copy code
prefect deployments inspect 'flow-name/deployment-name'
3) If you don’t want it, delete it:
Copy code
prefect deployments delete 'flow-name/deployment-name'
4) If it’s only a Flow (no deployment) that you’re seeing, that’s expected after any run. You can leave it, or stop running that flow in that workspace. (There isn’t a standard CLI to delete Flow objects; they’re created when runs happen.) Also double‑check both your local and Coolify environments are pointed at the same API/workspace (PREFECT_API_URL). If they are, you’ll see the same objects in both UIs. If you paste the output of: -
prefect deployments ls
(just the line for the unexpected one), and -
prefect deployments inspect 'flow-name/deployment-name'
I can help confirm how it was created and the cleanest way to reconcile it with your prefect.yaml.
g
@Marvin and the other way round, deployments which are specified in the .yaml are not occuring in the UI, because as shown above for the docker exec command, this was specific for one deployment only.
m
thought for 32.3 seconds
You’ve got it: if you’ve only ever run an ad‑hoc deploy for one entrypoint inside the container, only that deployment will show up. The deployments defined in
prefect.yaml
won’t appear in the UI until you actually register them with
prefect deploy
reading that YAML. What to do - Inside the container, run from the project root (where
prefect.yaml
lives) and deploy all YAML-defined deployments:
Copy code
prefect deploy --all
Or, select specific ones by name pattern:
Copy code
prefect deploy -n 'my-flow/my-deployment' -n 'other-flow/*'
- Verify what’s currently registered:
Copy code
prefect deployments ls
If you see old ad‑hoc deployments you don’t want, remove them:
Copy code
prefect deployments delete 'flow-name/deployment-name'
- Ensure the container points at the correct API/workspace: - Self-hosted/Server: set
PREFECT_API_URL
in the container to your Coolify Prefect API - Cloud: set
PREFECT_API_KEY
and workspace settings If the API target differs between local and Coolify, the UIs will show different deployments. Makefile simplification - If you want to deploy everything in `prefect.yaml`:
Copy code
docker-deploy:
  	docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") bash -lc 'cd /app && prefect deploy --all'
Replace
/app
with your project root inside the container. - If you want only a subset, use `-n`:
Copy code
docker exec -it $$(docker ps -aqf "name=goal100-mastr-pipeline") bash -lc 'cd /app && prefect deploy -n "download_update_flow/my-deployment" -n "mvp_test_flow/*"'
Tips - Keep
build:
and
push:
as
null
in
prefect.yaml
if you’re already shipping code in the image;
prefect deploy
will just register deployments. - If you’re unsure which names to pass to
-n
, share the
deployments:
section of your
prefect.yaml
and I’ll suggest the exact
-n
values. Docs: https://docs-2.prefect.io/latest/guides/prefect-deploy/
g
@Marvin you've been referring to that it could be, Deployments are only stored/saved in the API, what does that mean?
m
thought for 83.9 seconds
Great question. In Prefect 2.x, “deployments are stored in the API” means: - A deployment is a record in your Prefect backend (Cloud or Server) that contains the metadata needed to run a flow: flow entrypoint, parameters, schedule, work pool/queue, storage/image references, tags, etc. - When you run
prefect deploy
(or
prefect deployment apply
), Prefect sends that deployment specification to the API. The API persists it, and that’s what you see in the UI and what workers poll to pick up runs. - Your local files (like
prefect.yaml
) are just the source/config describing what you want deployed. They are not the deployment themselves. Nothing shows up in the UI until you register it with the API. - Because the deployment lives in the API: - You can see it in the UI from any machine/environment pointed at the same workspace. - Workers poll the API for deployments and schedules to create flow runs. - You can delete/update deployments via CLI or UI without editing local files (though best practice is to keep
prefect.yaml
as the system of record and re-run
prefect deploy
). A helpful mental model: - prefect.yaml: your desired state (version-controlled spec). - prefect deploy: syncs desired state to the API. - API/UI: the actual, current state that workers read from and that you observe. If you want to verify where you’re “saving” deployments, check the environment’s Prefect target: - Cloud/Server URL and workspace:
prefect config view
shows
PREFECT_API_URL
and workspace context. - If your local machine and Coolify container point to different `PREFECT_API_URL`s, you’ll see different deployments in their UIs. To reconcile drift: - Run
prefect deployments ls
to see what the API currently has. - Delete any strays:
prefect deployments delete 'flow-name/deployment-name'
. - Re-deploy from your `prefect.yaml`:
prefect deploy --all
(or
-n
selections).
g
@Marvin in the prefect.yaml I don't understand the push and pull parts
m
thought for 339.0 seconds
Great question — the push and pull sections in prefect.yaml can be confusing at first. Here’s the quick mental model in Prefect 3.x: - build: runs locally during prefect deploy to create artifacts (e.g., a Docker image) - push: runs locally right after build during prefect deploy to upload those artifacts somewhere (e.g., push the image to a registry) - pull: runs remotely on the worker every time a flow run starts; it prepares the runtime environment (e.g., clone your repo or download code from storage) Key point: build/push happen once at deploy time on your machine. pull happens on every run in the remote execution environment. Docs: - Prefect YAML overview: prefect.yaml explained - Pull step APIs: pull steps - Utility steps (shell, pip): utility steps What each section is for - build (optional) - Create artifacts locally: e.g., build a Docker image that contains your flow code and dependencies. - Example step:
prefect_docker.deployments.steps.build_docker_image
- push (optional) - Upload what you built in build: e.g., push the Docker image to a registry. - Example step:
prefect_docker.deployments.steps.push_docker_image
- pull (usually required) - Prepare code and environment where the flow actually runs: - Pull code from Git:
prefect.deployments.steps.pull.git_clone
- Download an artifact from storage:
prefect.deployments.steps.pull.pull_from_remote_storage
(supports fsspec URLs like s3://, gs://, etc.) - Set working directory:
prefect.deployments.steps.pull.set_working_directory
- Install deps at runtime:
prefect.deployments.steps.utility.pip_install_requirements
- Use a block at runtime:
prefect.deployments.steps.pull.pull_with_block
Templating and step IDs - Steps can have an
id
. Later steps can reference outputs from earlier ones using Jinja, e.g.
{{ clone.directory }}
. - Environment variables:
{{ $ENV_VAR }}
- Variables and block references can also be templated; block references in pull are resolved at runtime (safer for secrets). Examples 1) Git-based deployment (no Docker) - Your worker will clone the repo on every run (pull only).
Copy code
name: my-project
prefect-version: ">=3.0.0"

pull:
  - prefect.deployments.steps.pull.set_working_directory:
      directory: /opt/prefect/flows
  - id: clone
    requires: gitpython
    prefect.deployments.steps.pull.git_clone:
      repository: <https://github.com/acme/prefect-flows.git>
      branch: main

deployments:
  - name: etl
    entrypoint: flows/etl.py:etl
    work_pool:
      name: my-pool
2) Docker image deployment - Build/push once at deploy time; worker just runs the image. You may still set a working directory in pull.
Copy code
name: my-docker-project
prefect-version: ">=3.0.0"

build:
  - id: image
    requires: prefect-docker
    prefect_docker.deployments.steps.build_docker_image:
      image_name: <http://ghcr.io/acme/etl|ghcr.io/acme/etl>
      tag: "{{ $GIT_COMMIT_SHA | default('latest') }}"

push:
  - requires: prefect-docker
    prefect_docker.deployments.steps.push_docker_image:
      image_name: "{{ image.image_name }}"
      tag: "{{ image.tag }}"

pull:
  - prefect.deployments.steps.pull.set_working_directory:
      directory: /opt/prefect/flows

deployments:
  - name: etl
    entrypoint: flows/etl.py:etl
    work_pool:
      name: my-docker-pool
    job_variables:
      image: "<http://ghcr.io/acme/etl:{{|ghcr.io/acme/etl:{{> $GIT_COMMIT_SHA | default('latest') }}"
3) Remote storage artifact (pull from S3) - Worker downloads code at runtime from storage. ``` name: my-storage-project prefect-version: ">=3.0.0" pull: - prefect.deployments.steps.pull.pull_from_remote_storage: url: "s3://my-bucket/prefect-artifacts/flows-{{ $GIT_COMMIT_SHA }}.tar.gz" - prefect.deployments.steps.pull.set_working_directory:
directory: ./flows deployments: - name: etl entrypoint: flows/etl.py:etl work_pool: name: my-pool ``` Supported steps you’ll commonly use - Pull:
git_clone
,
pull_from_remote_storage
,
set_working_directory
,
pull_with_block
,
pip_install_requirements
,
run_shell_script
- Build:
prefect_docker.deployments.steps.build_docker_image
,
pip_install_requirements
,
run_shell_script
- Push:
prefect_docker.deployments.steps.push_docker_image
,
run_shell_script
Differences from Prefect 2.x - No
prefect deployment build
(use
prefect deploy
). - No
Deployment.build_from_flow()
and no GitHub storage blocks. In 3.x, you use
flow.from_source(...).deploy(...)
or project-based
prefect deploy
, and you model packaging via build/push/pull steps. - The pull section replaces the old “storage” attribute by explicitly defining how runtime environments fetch code. If you can share your current prefect.yaml and how you want to ship your code (Docker image, Git clone each run, cloud storage, etc.), I can tailor the push/pull steps for your setup.
g
@Marvin in the local setup without containers, how do i stop a server and clean the API via CLI
m
thought for 77.7 seconds
Got it. Assuming Prefect 3.x and a local (non-container) setup: Stop the local server - If it’s running in the foreground (you started it in a terminal): - Press Ctrl+C in that terminal - If it was started in the background: - Run:
Copy code
prefect server stop
Clean/reset the local API database - This drops and recreates all Prefect tables (you’ll lose flows, deployments, runs, work pools/queues, blocks, variables, automations, artifacts, etc.):
Copy code
prefect server database reset -y
Start the server again (optional)
Copy code
prefect server start
Does “clean the API” mean a full reset like above, or did you want to preserve some resources (e.g., blocks) and only clear runs? I can suggest more targeted commands if needed.
g
@Marvin local setup prefect 2.14.16 - to find a workflow for clean deployment. • stopped running server via terminal ctrl + c • rerun make setup • deleted .prefect/flows.json • I deleted the existing deployments from the prefect.yaml • restarted
prefect server start
• previously deployed flows still show up, why? How to remove those if they are not present in the prefect.yaml?
m
thought for 111.7 seconds
You're on Prefect 2.14.16 — got it. What you’re seeing is expected: deployments and flows are stored in the server’s database. Editing or deleting items from prefect.yaml or local project files does not remove what’s already been registered in the API. That’s why they still show up after a server restart. You have two cleanup options: Option A: Delete existing deployments from the API (surgical) - List what’s there:
Copy code
prefect deployment ls
- Delete specific deployments:
Copy code
prefect deployment delete <FLOW_NAME>/<DEPLOYMENT_NAME>
- Or delete them all:
Copy code
prefect deployment delete --all
Note: In Prefect 2.x there isn’t a CLI to delete “flows” themselves; after deleting deployments they may still appear in the UI until there are no runs referencing them. To completely wipe all metadata, use Option B. Option B: Reset the local API database (nuclear option) - Stop the server if it’s running (Ctrl+C is fine, or):
Copy code
prefect server stop
- Reset the DB:
Copy code
prefect server database reset -y
- Start the server again:
Copy code
prefect server start
This deletes everything in the API (deployments, flows, runs, schedules, blocks, variables, etc.). Why .prefect/flows.json and prefect.yaml edits didn’t change the UI - prefect.yaml only controls future
prefect deploy
actions; it does not remove resources already registered with the API. - .prefect/flows.json is local project metadata and doesn’t affect what’s in the server database. If you tell me whether you want to wipe everything or just remove a subset of deployments, I can give you exact commands tailored to your current list.
g
@Marvin one flow has been deployed remotely not from the prefect.yaml but by specifying in the cli prefect deploy entrypoint:name_of_flow . Can I reversely get the infos that should be entered into the .yaml in the .yaml format?
m
thought for 209.6 seconds
Short answer: there’s no built-in “export to YAML” for an existing deployment in Prefect 2.14.16. Deployments created via CLI (e.g.,
prefect deploy entrypoint:flow
) live in the API and Prefect doesn’t auto-generate a prefect.yaml from them. You can, however, retrieve all the details and then copy them into a prefect.yaml yourself. Step 1 — Find and inspect the deployment - List deployments:
Copy code
prefect deployment ls
- Inspect one to see all of its fields (name, entrypoint, parameters, tags, work pool/queue, schedule, etc.):
Copy code
prefect deployment inspect "<FLOW_NAME>/<DEPLOYMENT_NAME>"
Step 2 — Map inspect output to prefect.yaml Here’s a template you can fill in based on the inspect output:
Copy code
name: my-project
prefect-version: ">=2.14.0"

deployments:
  - name: <DEPLOYMENT_NAME>              # from 'name'
    entrypoint: <path/to/file.py:flow>   # from 'entrypoint'
    description: <DESCRIPTION>           # from 'description' (optional)
    parameters:                          # from 'parameters' (optional)
      key: value
    tags:                                # from 'tags' (optional)
      - tag1
      - tag2
    work_pool:
      name: <WORK_POOL_NAME>             # from 'work_pool_name'
      work_queue_name: <WORK_QUEUE_NAME> # from 'work_queue_name' (optional)
    job_variables:                       # maps to worker job vars/infra_overrides (optional)
      env: {}
      # add other keys relevant for your worker, e.g. 'working_dir', 'stream_output', etc.

    # Choose ONE schedule style if your deployment has a schedule
    # For cron schedules:
    schedule:
      cron: "0 * * * *"
      timezone: "UTC"
      active: true

    # For interval schedules:
    # schedule:
    #   interval: "3600"   # seconds
    #   timezone: "UTC"
    #   active: true
Notes and tips - Not everything you see in
inspect
has a 1:1 field in prefect.yaml, but the important runtime items do: - name -> deployments[].name - entrypoint -> deployments[].entrypoint - parameters -> deployments[].parameters - tags -> deployments[].tags - work_pool_name -> deployments[].work_pool.name - work_queue_name -> deployments[].work_pool.work_queue_name - schedules -> deployments[].schedule (use cron or interval as shown) - infra_overrides / worker job config -> deployments[].job_variables - If you were using a docker image or other packaging, you can also add optional build/push/pull steps in prefect.yaml (2.x supports this), but they are not required for local/standard setups. - After you create prefect.yaml, you can redeploy with:
Copy code
prefect deploy
- If you want to retire the old deployment, delete it:
Copy code
prefect deployment delete "<FLOW_NAME>/<DEPLOYMENT_NAME>"
Docs for 2.x - Deployments (2.x) - Using prefect deploy (2.x) If you share the output of
prefect deployment inspect "<flow>/<deployment>"
, I can turn it into a ready-to-use prefect.yaml snippet for you.
g
@Marvin again version 2.14.16, Function-Parameters of the flow to be deployed are already defined in the function/flow definition in the .py of the flow. Must these be entered into the .yaml as well? Right now we define the scheduling in .yaml and the other parameters passed to the flow in the .py function/flow definition.
m
thought for 50.3 seconds
Short answer: No — you don’t have to repeat parameters in the YAML if your flow function defines defaults. In Prefect 2.14.16: - If a parameter has a default in your flow function, you can omit it from the deployment YAML; scheduled runs will use the function’s default. - If a parameter is required (no default), you must supply it somewhere: in the deployment’s
parameters
, via the UI when triggering a run, or at runtime via CLI. Parameter precedence - CLI at run time:
prefect deployment run <flow/deploy> -p key=value
overrides everything - Deployment YAML
parameters
overrides flow defaults - Flow function defaults are used if neither of the above provides a value Examples 1) All parameters have defaults — YAML can only define the schedule
Copy code
# flows/etl.py
from prefect import flow

@flow
def etl(color: str = "blue", limit: int = 100):
    ...
Copy code
# prefect.yaml (or deployment.yaml)
deployments:
  - name: etl
    entrypoint: flows/etl.py:etl
    schedule:
      cron: "0 * * * *"
      timezone: "UTC"
Scheduled runs use
color="blue", limit=100
unless you override them. 2) Required parameter — provide it in YAML or at run time
Copy code
@flow
def etl(color: str, limit: int = 100):
    ...
Copy code
deployments:
  - name: etl
    entrypoint: flows/etl.py:etl
    parameters:
      color: "green"     # required because no default in code
    schedule:
      cron: "0 * * * *"
      timezone: "UTC"
Or override at run time:
Copy code
prefect deployment run etl/etl -p color='"red"'
Notes - If you change the flow’s signature or defaults, redeploy so the API/UI schema reflects the update. - Parameters provided in YAML or CLI must be JSON-serializable. Prefer simple types (str, int, float, bool, lists/dicts). If you need complex objects, pass a serializable representation. If you want, share your flow signature and current YAML and I’ll confirm whether anything is missing for scheduled runs to work reliably.
g
@Marvin more concrete: in the local version of the production branch version under pull I in the prefect.yaml
Copy code
# pull section allows you to provide instructions for cloning this project in remote locations
pull:
- prefect.deployments.steps.set_working_directory:
    directory: /Users/Name/Documents/project_repo
which is the local working directory. While the path on the server, in the containers coolify builds the path is just /prefect, so outside of the working directory, a persistent storage 'around' the containers. How and why?
m
thought for 172.3 seconds
Thanks for the concrete example. In Prefect 2.14.16, the
pull
steps run on the worker at flow-run time. Your current config:
Copy code
pull:
- prefect.deployments.steps.set_working_directory:
    directory: /Users/Name/Documents/project_repo
will only work if the worker is running on that same machine and that exact path exists. It does not fetch code; it just “cd”s into that path. If the worker runs on a different host or under a different user, this will fail. You have a few safer options: Option 1: Clone the repo on each run (portable) - Let the worker fetch the production branch and then set the working dir to the cloned path.
Copy code
pull:
  - id: clone
    requires: gitpython
    prefect.deployments.steps.git_clone:
      repository: git@github.com:your-org/project_repo.git
      branch: production
  - prefect.deployments.steps.set_working_directory:
      directory: "{{ clone.directory }}"
- Keep your
entrypoint
relative to the repo root (e.g.,
flows/my_flow.py:my_flow
). Option 2: Set the worker’s working directory via job variables (no pull step needed) - If the worker is on the same machine and you want to use your local files, put the path in the deployment’s job variables instead of a pull step:
Copy code
deployments:
  - name: my-deploy
    entrypoint: flows/my_flow.py:my_flow
    work_pool:
      name: process-pool
    job_variables:
      working_dir: /Users/Name/Documents/project_repo
- This makes the run start in that directory without an extra step. Still brittle across machines, but cleaner if truly local. Option 3: Keep the pull step but avoid user-specific absolute paths - Use an environment variable fallback:
Copy code
pull:
  - prefect.deployments.steps.set_working_directory:
      directory: "{{ $PROJECT_ROOT | default('/opt/prefect/flows') }}"
- Set
PROJECT_ROOT
on each worker host. Notes - Your step path is fine in 2.14.16:
prefect.deployments.steps.set_working_directory
is the canonical form. - If your entrypoint is relative, you must ensure the working directory at runtime matches the repo layout; otherwise, make
entrypoint
absolute (less common). - If you also need dependencies, add a runtime install step:
Copy code
- prefect.deployments.steps.pip_install_requirements:
    requirements: requirements.txt
If you can confirm where your worker runs (same machine vs remote), I can recommend the best option and provide an exact
prefect.yaml
snippet for your setup. Docs (2.x): - Using prefect deploy (2.x) - Deployments (2.x)
g
@Marvin would the local version, which is not containerized work without specifying anything for pull:?
m
thought for 274.8 seconds
Short answer: Yes, it can work without any pull steps — as long as the worker can see your code on disk and your entrypoint resolves correctly at runtime. What “no pull” really means - Prefect will not clone or download your code. The worker just tries to import the flow from the
entrypoint
path you gave the deployment. - This succeeds if: - The code is already present on the same machine where the worker runs, and - The
entrypoint
is either an absolute path or a path that’s valid relative to the worker’s working directory. Recommended minimal setup for local, non-containerized runs - Omit
pull:
entirely and set a working directory via job variables so your relative entrypoint always resolves:
Copy code
deployments:
  - name: my-deploy
    entrypoint: flows/my_flow.py:my_flow
    work_pool:
      name: process-pool
    job_variables:
      working_dir: /Users/Name/Documents/project_repo
- Alternatively, use an absolute `entrypoint`:
Copy code
deployments:
  - name: my-deploy
    entrypoint: /Users/Name/Documents/project_repo/flows/my_flow.py:my_flow
    work_pool:
      name: process-pool
- If you omit both
pull
and
job_variables.working_dir
, the worker must be started from your project directory so the relative
entrypoint
resolves. When you should add a pull step - If the worker is on a different machine, or you want consistency across restarts/users, add a pull step like
git_clone
to fetch the code at run time. Docs (2.x): - Using prefect deploy (2.x) - Overriding job variables (working_dir, env, etc.) If you share your current
entrypoint
and where your worker runs from, I can confirm the simplest working config.
g
@Marvin so in our containerized version, since the codebase where the entrypoints point to is within the same dir where the server is started, we do not even need to define pull?
m
thought for 45.3 seconds
Short answer: Yes — if the code is already present in the runtime environment of the worker container (baked into the image or mounted as a volume) at the path your entrypoint expects, you can omit pull entirely. Important clarifications - The server’s working directory doesn’t matter for execution. What matters is the filesystem inside the container that runs the flow (the worker job). - With no pull steps, Prefect will not clone or download code; it will just import your flow from the entrypoint path inside the running container. Two common containerized patterns that don’t need pull 1) Bake code into the image - Build an image that contains your repo at, say, /app. - Set your entrypoint to the in-container path and optionally set working_dir via job variables.
Copy code
deployments:
  - name: my-deploy
    entrypoint: /app/flows/my_flow.py:my_flow
    work_pool:
      name: docker-pool
    job_variables:
      image: <http://ghcr.io/acme/project:prod|ghcr.io/acme/project:prod>
      working_dir: /app
2) Bind mount your local code into the container - Mount the host repo into the container and set working_dir (or use an absolute entrypoint).
Copy code
deployments:
  - name: my-deploy
    entrypoint: /app/flows/my_flow.py:my_flow
    work_pool:
      name: docker-pool
    job_variables:
      image: <http://ghcr.io/acme/base:latest|ghcr.io/acme/base:latest>
      working_dir: /app
      volumes:
        - "/Users/Name/Documents/project_repo:/app:ro"
When you would add pull - If the worker container shouldn’t depend on local mounts and you want it to fetch code on start (e.g., clone a Git repo), add a
git_clone
pull step and set working_dir accordingly. If you can share which worker type you’re using (Docker/Kubernetes) and whether you bake the code into the image or mount it, I can provide an exact prefect.yaml snippet for your setup.
g
@Marvin what is meant by bake?
m
thought for 17.5 seconds
“Bake” just means: put your code and dependencies into the container image at build time so they’re already there when the container starts. No cloning, no mounting, no pull steps needed at runtime. Why bake - Reproducible: every run uses the exact same code + libs - Self-contained: the worker only needs the image; no Git or cloud storage access required at runtime - Simpler deployments: you can omit
pull:
entirely How to bake your project - Create a Dockerfile that installs dependencies and copies your code into the image:
Copy code
FROM python:3.11-slim

# Set a working directory inside the image
WORKDIR /app

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy your project code into the image
COPY . /app

# (optional) Prefect config for your environment
# ENV PREFECT_API_URL=<http://prefect-server:4200/api>
- Build (and push if using a registry):
Copy code
docker build -t <http://ghcr.io/acme/project:prod|ghcr.io/acme/project:prod> .
# docker push <http://ghcr.io/acme/project:prod|ghcr.io/acme/project:prod>
- Point your Prefect 2.14 deployment at that image and working directory:
Copy code
deployments:
  - name: my-deploy
    entrypoint: /app/flows/my_flow.py:my_flow
    work_pool:
      name: docker-pool
    job_variables:
      image: <http://ghcr.io/acme/project:prod|ghcr.io/acme/project:prod>
      working_dir: /app
Compare to other approaches - Bind mount (not baked): Mount host code into the container at runtime via
volumes
job variable. Faster for dev, but couples runs to host paths. - Pull steps: Have the container fetch code at runtime (
git_clone
,
pull_from_*
). Useful if you want to run “latest” without rebuilding the image, but adds runtime dependencies. In your containerized setup, if the image already contains your code at the path your
entrypoint
uses, you can safely omit
pull:
.
g
@Marvin in the src/flow_name.py, the entrypoint of the deployment and the flow-function definition I set a boolean parameter for the flow in the function definiton as False. Can I override this default with the prefect.yaml and would this be wise?
m
thought for 270.8 seconds
Short answer: yes. In Prefect 3.x, parameters you set under a deployment in prefect.yaml become that deployment’s default parameters and will override the flow function’s default when runs are created from that deployment. It’s a common and reasonable pattern. Example Flow code (default is False):
Copy code
from prefect import flow

@flow
def my_flow(do_extra: bool = False):
    if do_extra:
        print("Doing the extra thing")
    else:
        print("Skipping the extra thing")
prefect.yaml with two deployments overriding the default differently:
Copy code
name: my-project
prefect-version: ">=3.0.0"

deployments:
  - name: prod
    entrypoint: src/flow_name.py:my_flow
    parameters:
      do_extra: true   # overrides the function default
    work_pool:
      name: default

  - name: dry-run
    entrypoint: src/flow_name.py:my_flow
    parameters:
      do_extra: false
    work_pool:
      name: default
Parameter precedence - Highest: run-time overrides when you create a run (CLI, UI, or API) - CLI example:
Copy code
prefect deployment run my_flow/prod -p do_extra=false --watch
Note: values are parsed as JSON; use `true`/`false` not `"true"`/`"false"`. - Next: deployment defaults from
prefect.yaml
(or from
.deploy(parameters=...)
) - Lowest: the flow function’s default in code Best practices and caveats - Use the flow’s default as a safe local default (what happens if someone runs the script directly). - Use deployment parameters to encode environment- or schedule-specific behavior (e.g., “prod” turns on extra work, “dry-run” turns it off). - Prefer clear deployment names that reflect the behavior (e.g.,
my_flow/prod
vs
my_flow/dry-run
). - Don’t quote booleans in YAML or they’ll become strings (`true`/`false`, not `"true"`/`"false"`). - If you change parameters in
prefect.yaml
, re-run
prefect deploy
so the server gets the updated deployment. - Parameters must match the flow’s signature; mismatches will error at run time. - Job variables in the deployment are separate from flow parameters; don’t confuse them. If you want, paste your
prefect.yaml
snippet and I’ll sanity-check the parameters section.
g
@Marvin what is the difference between
prefect server database upgrade
and
prefect server database reset -y
and what's with the -y flag?
m
thought for 66.5 seconds
Short version: - prefect server database upgrade: Runs Alembic migrations to bring your Prefect Server database schema up to the target revision (default: latest “head”). Intended to preserve your data. You can preview with --dry-run and target a specific revision with -r. - prefect server database reset: Drops all Prefect tables and recreates them at the current schema. This is destructive and wipes all data (flows, runs, artifacts, automations, work pools, etc.). What’s -y? - -y is short for --yes. It skips the interactive confirmation prompt so the command can run non‑interactively (useful in automation/CI). Use with extra care on reset. Verified CLI help:
Copy code
prefect server database upgrade --help
prefect server database reset --help
Examples:
Copy code
# Safely migrate schema to latest
prefect server database upgrade -y

# Preview what would run without applying changes
prefect server database upgrade --dry-run

# Destructively wipe and recreate all Prefect tables
prefect server database reset -y
Notes: - These commands apply to self-hosted Prefect Server (not Prefect Cloud’s managed DB). - In production, prefer upgrade; avoid reset unless you intentionally want a clean slate.
g
@Marvin I still don't understand what the upgrade command achieves and what the target revision would be. Please explain in more detail and in less technical terms, or explain these terms as well
m
thought for 123.4 seconds
Great question—here’s a plain-English breakdown. What “upgrade” does - Think of the Prefect database like the shelves in a library. As Prefect adds features, it may need to add or rearrange shelves (new tables/columns/indexes). - A database “upgrade” applies those shelf changes without throwing away any of your books (your data). - When you run:
Copy code
prefect server database upgrade
Prefect applies all the pending, ordered changes (called “migrations”) your current database needs to match the version of Prefect you’ve installed. What is a “revision” and “head”? - A “revision” is one step in the sequence of changes to the database layout. Each revision has an ID and builds on the previous one. - “head” just means “the most recent revision that ships with your installed Prefect version.” - Target revision (-r): You can stop at a specific revision if you need to (rare). By default, upgrade goes to “head,” which is what you almost always want. When should you run “upgrade”? - After you upgrade Prefect (the software) to a new version that includes schema changes, especially if you’ve disabled automatic migrations. - Prefect Server can run migrations automatically on startup. This is controlled by the
PREFECT_SERVER_DATABASE_MIGRATE_ON_START
setting (defaults to on). If it’s off, you’ll need to run the upgrade command manually. - Docs: - Server CLI: database commands - Settings reference (migrate on start) What “reset” does - “Reset” is the nuclear option:
Copy code
prefect server database reset -y
It drops all Prefect tables and recreates them empty. This wipes everything (flows, runs, blocks, automations, work pools, artifacts, etc.). Use it only when you want a completely clean slate (e.g., local dev/testing). What’s the -y flag? -
-y
(short for
--yes
) skips the “Are you sure?” prompt. Good for automation, risky for destructive commands like
reset
. Helpful tips - Preview without changing anything:
Copy code
prefect server database upgrade --dry-run
- On very large databases, upgrades may take time; you can increase the DB timeout if needed (e.g.,
PREFECT_API_DATABASE_TIMEOUT=600
). - More details: - Database maintenance and migrations - Database migration commands API Summary - Use “upgrade” to bring your database schema up to date with your installed Prefect—keeps your data intact. - “Revision” = a single step in the schema change history; “head” = the latest step. - “reset” destroys and recreates all tables—use sparingly. -
-y
just answers “yes” to prompts so the command runs non-interactively.
g
@Marvin ok, so as long as the prefect version is not updated and everythings running smoothly, a new flow-deployment or deployed changes in our hostet prefect-server setup would not even need
prefect server database upgrade
?
m
thought for 127.1 seconds
Short answer: Yes—if you haven’t upgraded your Prefect Server version, routine actions like creating new deployments or updating your flow code do not require running
prefect server database upgrade
. Why: - Database “upgrades” only matter when the Prefect Server software introduces schema changes (new/changed tables/columns). If your server version hasn’t changed, the schema it needs is already in place. - New deployments, schedules, parameters, etc. just write data into the existing schema and don’t need migrations. When you would need an upgrade: - You upgrade Prefect Server to a new version that includes schema changes. By default, Server will migrate automatically on startup; if you’ve disabled that, you’d run:
Copy code
prefect server database upgrade -y
- You upgrade the Prefect Python client in your deployment environment significantly ahead of your server and it starts using features that require a newer server schema. In that case, upgrade your server (and let it migrate) or align client and server versions. Notes and links: - Auto-migrate on start is controlled by
PREFECT_SERVER_DATABASE_MIGRATE_ON_START
(defaults to True): https://docs-3.prefect.io/v3/api-ref/settings-ref - Server database CLI docs: https://docs-3.prefect.io/v3/how-to-guides/self-hosted/server-cli - Database maintenance and migrations: https://docs-3.prefect.io/v3/advanced/database-maintenance And just to reiterate:
prefect server database reset -y
is destructive and only for wiping everything to start fresh—not needed for normal deployments.