Task state store in Apache Airflow®
Task state store in Apache Airflow®
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.
The task state store feature is experimental and might be subject to change in future versions based on user feedback.
Assumed knowledge
To get the most out of this guide, you should have an understanding of:
- Basic Airflow concepts. See Introduction to Apache Airflow.
- Airflow operators. See Airflow operators.
- Airflow decorators. See Introduction to the TaskFlow API and Airflow decorators.
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 does not 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 retry-safe 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:
- In your task code using the methods available in the
task_state_storekey of the Airflow context in:- A
@task-decorated function using the TaskFlow API. - A
python_callablepassed to aPythonOperator. - The
executemethod of a custom operator, created by subclassingBaseOperatoror any existing traditional operator.
- A
- In the Airflow UI
- With the Airflow REST API
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 keep the entry indefinitely. The cleanup process skips the entry, regardless of the environment default.None, the default, to fall back to the environment’sAIRFLOW__STATE_STORE__DEFAULT_RETENTION_DAYSconfiguration (default: 30 days).
get(key, default=None) returns the stored value, or default if the key does not 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 does not 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.
TaskFlow API
PythonOperator
Custom operator
Extended traditional operator
Task state store in the Airflow UI
You can view and edit task state store entries for any task instance in the Airflow UI.

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_daysconfiguration. - Never: The entry never expires.
- Custom: The entry expires at the date and time you select.

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): ReturnTrueif the job is still running and can be reconnected to.is_job_succeeded(status): ReturnTrueif 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, orNoneif 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 does not 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 do not 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.