Results are the bedrock of many Prefect features - most notably transactions and caching - and are foundational to the resilient execution paradigm that Prefect enables. Any return value from a task or a flow is a result. By default these results are not persisted and no reference to them is maintained in the API. Enabling result persistence allows you to fully benefit from Prefect’s orchestration features.Documentation Index
Fetch the complete documentation index at: https://docs.prefect.io/llms.txt
Use this file to discover all available pages before exploring further.
Result storage is where Prefect writes serialized flow and task return values so they can be reused
by Prefect features such as retries, caching, and reading a run’s return value later. It does not
change where your flow code writes files, uploads datasets, or stores artifacts that your code creates
directly. For example, if your flow calls an S3 client to upload a CSV, that upload still uses the
location specified in your flow code.
Configuring result persistence
There are four categories of configuration for result persistence:- whether to persist results at all: this is configured through
various keyword arguments, the
PREFECT_RESULTS_PERSIST_BY_DEFAULTsetting, and thePREFECT_TASKS_DEFAULT_PERSIST_RESULTsetting for tasks specifically. - what filesystem to persist results to: this is configured through the
result_storagekeyword, thePREFECT_DEFAULT_RESULT_STORAGE_BLOCKsetting, or a server-side default result storage block. A configured default result storage block also enables result persistence by default. - how to serialize and deserialize results: this is configured through
the
result_serializerkeyword and thePREFECT_RESULTS_DEFAULT_SERIALIZERsetting. - what filename to use: this is configured through one of
result_storage_key,cache_policy, orcache_key_fn.
Default persistence configuration
Once result persistence is enabled - whether through thePREFECT_RESULTS_PERSIST_BY_DEFAULT setting or
through any of the mechanisms described below - Prefect’s default
result storage configuration is activated.
If you enable result persistence and don’t specify a filesystem block, your results will be stored locally.
By default, results are persisted to ~/.prefect/storage/.
You can configure the location of these results through the PREFECT_LOCAL_STORAGE_PATH setting.
Enabling result persistence
In addition to thePREFECT_RESULTS_PERSIST_BY_DEFAULT and PREFECT_TASKS_DEFAULT_PERSIST_RESULT settings,
result persistence can also be enabled or disabled on both individual flows and individual tasks.
Specifying a non-null value for any of the following keywords on the task decorator will enable result
persistence for that task:
persist_result: a boolean that allows you to explicitly enable or disable result persistence.result_storage: accepts either a string reference to a storage block or a storage block class that specifies where results should be stored.result_storage_key: a string that specifies the filename of the result within the task’s result storage.result_serializer: a string or serializer that configures how the data should be serialized and deserialized.cache_policy: a cache policy specifying the behavior of the task’s cache.cache_key_fn: a function that configures a custom cache policy.
persist_result=True, result_storage, or result_serializer on a flow will enable
persistence for that flow.
Enabling persistence on a flow enables persistence by default for its tasksEnabling result persistence on a flow through any of the above keywords will also enable it for all
tasks called within that flow by default.Any settings explicitly set on a task take precedence over the flow settings.Additionally, the
PREFECT_TASKS_DEFAULT_PERSIST_RESULT environment variable can be used to globally control the default persistence behavior for tasks, overriding the default behavior set by a parent flow or task.Result storage
You can configure the system of record for your results through theresult_storage keyword argument.
This keyword accepts an instantiated filesystem block, or a block slug. Find your blocks’ slugs with prefect block ls.
Note that if you want your tasks to share a common cache, your result storage should be accessible by
the infrastructure in which those tasks run. Integrations have cloud-specific storage blocks.
For example, a common distributed filesystem for result storage is AWS S3.
Using result storage with decoratorsWhen specifying
result_storage in @flow or @task decorators, you have two options:- Block instances: The block instance must be saved server-side or loaded from a saved block instance before it is provided to the
@taskor@flowdecorator. - String references: Use the format
"block-type-slug/block-name"for deferred resolution at runtime
Specifying a default filesystem
Alternatively, you can specify a different filesystem through thePREFECT_DEFAULT_RESULT_STORAGE_BLOCK setting.
Specifying a block document slug here configures the filesystem Prefect uses when result persistence is enabled.
For example:
Note that any explicit configuration of
result_storage on either a flow or task will override this default.Specifying a default filesystem server-side
If many flow runs should use the same result storage, you can set a server-side default. This is useful when you want every client, worker, and deployment connected to the same Prefect Cloud workspace or self-hosted Prefect server to write persisted results to a shared location without settingresult_storage in each flow or on every machine.
A configured server-side default result storage block also enables result persistence by default for
flows and tasks that do not explicitly opt out. You do not need to set PREFECT_RESULTS_PERSIST_BY_DEFAULT
in every worker environment when this default is configured.
The prefect experimental result-storage commands use your active CLI profile. Make sure the profile
is connected to the API where you want to set the default. If you are running Prefect locally, start
the server first:
- a running Prefect API, either Prefect Cloud or a self-hosted Prefect server
- a saved filesystem block, such as
S3Bucket,GcsBucket,AzureBlobStorageContainer, orLocalFileSystem
LocalFileSystem block:
- Install the storage integration anywhere that creates the block and anywhere that will run flows.
- uv
- pip
- Create and save a filesystem block for the bucket.
AwsCredentials block and pass it to S3Bucket:
- Set the saved block as the default result storage.
The saved block and its dependencies must be available wherever results are written and read. For example,
if the default is an
S3Bucket, install prefect-aws in the environment that creates the block and in
worker environments that run flows using the block.result_storage will use the S3 bucket for persisted flow and task return values.
More specific configuration still wins. Explicit
result_storage on a flow or task overrides the
server-side default. A local PREFECT_DEFAULT_RESULT_STORAGE_BLOCK setting also overrides the
server-side default for that profile.Result filenames
By default, the filename of a task’s result is computed based on the task’s cache policy, which is typically a hash of various pieces of data and metadata. For flows, the filename is a random UUID. You can configure the filename of the result file within result storage using either:result_storage_key: a templated string that can use any of the fields withinprefect.runtimeand the task’s individual parameter values. These templated values will be populated at runtime.cache_key_fn: a function that accepts the task run context and its runtime parameters and returns a string. See task caching documentation for more information.
name parameter passed to the task:
Result serialization
You can configure how results are serialized to storage using result serializers. These can be set using theresult_serializer keyword on both tasks and flows.
A default value can be set using the PREFECT_RESULTS_DEFAULT_SERIALIZER setting, which defaults to pickle.
Current built-in options include "pickle", "json", "compressed/pickle" and "compressed/json".
The result_serializer accepts both a string identifier or an instance of a ResultSerializer class, allowing
you to customize serialization behavior.
Caching results in memory
When running workflows, Prefect keeps the results of all tasks and flows in memory so they can be passed downstream. In some cases, it is desirable to override this behavior. For example, if you are returning a large amount of data from a task, it can be costly to keep it in memory for the entire duration of the flow run. Flows and tasks both include an option to drop the result from memory once the result has been committed withcache_result_in_memory:
Reading persisted results
After a flow or task run completes, you can read the persisted result back usingResultStore.
This is useful when you need to access a task’s return value outside of the flow that produced it,
for example in a separate script, a notebook, or a downstream pipeline.
Read a result with ResultStore
Use ResultStore to read a result record by its storage key.
The storage key is the filename of the result in your result storage location.
When you use result_storage_key on a task, the key is the formatted string you provided.
Otherwise, it is a hash derived from the task’s cache policy.
read method returns a ResultRecord object. Access the deserialized return value
through the .result attribute.
Always pass an explicit
result_storage when constructing ResultStore.
If you omit it, ResultStore attempts to resolve the default storage from Prefect settings,
which requires a running Prefect server or Prefect Cloud connection.End-to-end example: persist and then read a result
The following example persists a task result with a known storage key and then reads it back in a separate step:Read a result from a file directly
If you need to read a result file without using Prefect’sResultStore—for example, in an
environment where Prefect is not installed—you can deserialize the file manually.
Result files are JSON documents that contain a result field with the serialized data, and
a metadata field that describes the serializer used.
The encoding of the result field depends on the serializer:
- pickle (default): the value is base64-encoded pickled bytes.
- json: the value is a raw JSON string (not base64-encoded).
Inspect result metadata
EachResultRecord includes a metadata attribute with information about the serializer,
the storage key, and an optional expiration timestamp:
store.read() deserializes the result payload, so the serializer class used to
persist it must be importable in the current process. If it isn’t, the call raises: