Put secrets in Prefect blocks, not variables. The Prefect docs draw a clear line. Variables are unstructured JSON documents, while block schemas can have SecretStr fields, which are stored with additional encryption and not displayed by default in the UI.
The distinction in plain terms
A block is a typed, saved configuration object: a schema with named fields. A block document is a saved instance with real values, and you can create as many as you like. A block class is the Python class that loads a document and adds behaviour, such as an S3 bucket block with upload and download methods.
A variable is a loose JSON value that any flow can read. It is handy for small settings. It has no field types, so nothing marks a value as sensitive.
Why blocks suit credentials
Three properties matter for secrets.
- Field level protection. A SecretStr field is stored with additional encryption and hidden by default in the UI. A variable has no such marker.
- Rotation without redeploying. The docs say block documents can be created and updated in the UI or API, and give credential rotation as an example, so you can change a secret without touching deployments.
- Reuse. One credentials block can serve many flows, so there is one place to rotate and one place to review who can read it.
What "additional encryption" does not promise
Read the claim carefully. It describes how the field is stored and displayed. It does not say that code running a flow cannot read the value, since a flow that loads the block needs it to connect. Anyone who can write or deploy flow code that loads a block can use its credentials. So the effective control is who can deploy flows and which workers they run on.
Ask these questions for each credentials block:
- Which flows load it, and who can change those flows?
- Does the credential have only the permissions the flows need?
- Is there a rotation date, and who owns it?
- Does the block hold a long lived key where a short lived token would do?
A simple rule set
| Data | Where |
|---|---|
| Passwords, tokens, keys | Blocks with SecretStr fields |
| Non-sensitive toggles, names | Variables |
| Large or file-based secrets | Your secrets manager, referenced by a block or step |
Do not put a secret in a variable because it is easier to read in code. Convenience is how credentials end up in screenshots and exports.
Reviewing what you already have
List your variables and look for values that resemble credentials. Move any you find into a block, update the flows, then rotate the old values. For a wider view of where credentials leak in pipelines, see ETL pipeline secrets: where credentials leak.
Safeguard's dependency scanning and policy gates look at the code and packages your flows depend on. You can try a free scan at gold.safeguard.sh/scan.
Quick check
Is a Secret in a block hidden from flow code?
No. A flow that loads the block can read the value, since it needs it to connect. The protection concerns storage and UI display.
Can I rotate a block credential without redeploying?
The Prefect docs say block documents can be updated in the UI or API, and mention rotating credentials without touching deployments as a use.
Sources
- Blocks, Prefect documentation, fetched 19 October 2026.
Last reviewed: 19 October 2026.