Skip to main content
The task state store, added in Apache Airflow® 3.3, allows you to save information that persists between task retries. This makes the task state store suitable for storing external job IDs and intra-task checkpoints. In this guide, you’ll learn:
  • When to use the task state store, and how it compares to XCom, deferrable operators, and the asset state store.
  • How to set, get, delete, and clear values in the task state store.
  • How to view and edit entries in the Airflow UI and through the Airflow REST API.
  • How to create a custom operator that uses the task state store through the ResumableJobMixin.
  • How to configure the task state store.
The task state store holds information for a specific task instance. Airflow 3.3 also introduced the asset state store, which holds information attached to a specific Airflow asset. See the asset state store section of the advanced asset-based scheduling guide for more information.

Assumed knowledge

To get the most out of this guide, you should have an understanding of:

When to use the task state store

Use the task state store to persist information about a task instance’s own working state so that a later attempt of the same task instance, for example after a worker crash or retry, can access it. You can:
  • Store the ID of a long-running external process, such as a Spark job or a model fine-tuning job, so a retry reconnects to the running job instead of submitting a duplicate.
  • Store an intra-task checkpoint, such as the last page or offset processed, so a retry doesn’t restart from the beginning.
  • Store several pieces of state for one task instance, such as a status and a row count, and update them as the task runs.
When using the default task state store backend, Airflow saves entries to the metadata database, and stored values must be JSON serializable (except None). See task state store configuration for information on implementing a custom task state store backend.

Task state store vs. XCom

Both the task state store and XCom store small pieces of data attached to an individual task instance. The main difference is that Airflow clears XComs on retries, while task state entries persist.

Task state store vs. deferrable operators

The task state store, together with the ResumableJobMixin, and deferrable operators are both used in the context of long-running external jobs. Which to choose is often a question of personal preference. Deferrable operators free the worker slot while waiting and require a triggerer. The ResumableJobMixin keeps the worker slot but makes a synchronous operator crash-safe/durable by reconnecting to a running job.

Task state store vs. asset state store

The task state store and the asset state store have a similar key-value interface, but they are scoped differently. For more information on the asset state store, see the asset state store section of the advanced asset-based scheduling guide.

How to use the task state store

You have several options to interact with the task state store:
For custom operators built to resume a process after a retry a mixin is available, see ResumableJobMixin.

Task state store methods

The task state store exposes four methods: set, get, delete, and clear. set(key, value, *, retention=None) writes or overwrites the value for a key, in this case the PID of a long-running remote shell command. The keyword-only retention argument controls when the entry is automatically deleted:
  • A timedelta, to delete the entry after the given duration from the time of the write. Airflow computes the expiry timestamp on the worker before sending the value to the API server.
  • NEVER_EXPIRE, to exclude the entry from the automatic cleanup process and keep it until it is manually deleted.
  • None, the default, to fall back to the environment’s AIRFLOW__STATE_STORE__DEFAULT_RETENTION_DAYS configuration (default: 30 days).
get(key, default=None) returns the stored value, or default if the key doesn’t exist. For example, if a previous try of a task instance already started a long running shell command and saved the PID in the task state store, a later retry can get the PID in order to check if the command is still running, and if that is the case, wait on the existing command to finish instead of rerunning it from the start.
delete(key) deletes a single key. It does nothing if the key doesn’t exist.
clear() deletes all task state store keys for the task instance.

Task state store examples

The following examples start a long-running shell command on a remote host and store its process ID (PID) in the task state store with the set method. If the first try fails and the task is retried, it uses the get method to reconnect to the still-running command instead of launching a new one.

Task state store in the Airflow UI

You can view and edit task state store entries for any task instance in the Airflow UI.
Airflow UI task instance view with the Storage tab and Task State Store sub-tab selected, showing a my_num entry with its key, value, updated time, and expiry, and controls to add, clear, edit, and delete entries
To reach the task state store of a specific task instance, select the task instance square in the grid (1), open the Storage tab (2), then select the Task State Store tab. From here, you can:
  • Add an entry with Add Task State Store (3).
  • Remove all entries for the task instance with Clear All Task State Store (4).
  • Edit an entry (5).
  • Delete an entry (6).
When you select Add Task State Store (3), the Add Task State Store window appears. Enter a Key and Value for the entry, then choose when it expires:
  • Default (30 days): Use the default retention period for this Airflow environment, set by the default_retention_days configuration.
  • Never: The entry never expires.
  • Custom: The entry expires at the date and time you select.
Add Task State Store window in the Airflow UI with Key and Value fields and Expiration options for Default 30 days, Never, and Custom
Select Save to store the entry.

Task state store API endpoints

The Airflow REST API exposes task state store operations under each task instance’s state-store path:
The REST API limits each individual value to max_value_storage_bytes (64 KB by default) and rejects a larger value with a 422 error. For the request and response schemas of each operation, see the Airflow REST API reference.

ResumableJobMixin

For custom operators that submit one long-running external job and poll for its completion, you can use the ResumableJobMixin. After submitting the job, the mixin persists the external job ID to the task state store before polling starts. On a retry, the mixin reads the stored ID and reconnects to the running job instead of submitting a duplicate. The SparkSubmitOperator in the Apache Spark provider (6.2.0+) uses this mixin to reconnect to a running Spark application after a retry. To use the mixin, inherit from ResumableJobMixin, call execute_resumable(context) from your execute method, and write the following six methods to determine how to interact with your external system:
  • submit_job(context): Submit the job and return its external ID. The mixin stores this value in the task state store.
  • get_job_status(external_id, context): Query the external system and return its raw status string.
  • is_job_active(status): Return True if the job is still running and can be reconnected to.
  • is_job_succeeded(status): Return True if the job completed successfully.
  • poll_until_complete(external_id, context): Block until the job reaches a terminal state, and raise on failure.
  • get_job_result(external_id, context): Return the job result after completion, or None if not applicable.
On a retry, the mixin reads the stored ID and checks the current job status:
  • If the job is still active, the mixin reconnects and continues polling.
  • If the job already succeeded, the mixin returns the result without resubmitting.
  • If the job is in a terminal failure state, the mixin submits a fresh job.
The external_id_key class attribute sets the key used to store the job ID. The default is remote_job_id.
There is a small window between submit_job returning and the mixin persisting the ID to the task state store. If the worker crashes in that window, the retry doesn’t have the ID and submits a fresh job. For most workloads this window is negligible.

Task state store configuration

You can configure the task state store with the [state_store] configs.
The clear_on_success and default_retention_days options apply to the task state store only. They don’t affect the asset state store.
By default, the task state store and asset state store persist entries in the Airflow metadata database. To store entries elsewhere, you can provide a custom backend. See the Apache Airflow task and asset state store configuration documentation for more information.