NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #4773 most downloaded on PyPI
Provider package apache-airflow-providers-docker for Apache Airflow
Last release 5 days ago
29 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
6 years old
151 releases · first in 2020
One column per quarter.
- Add args to docker service ContainerSpec
Release Date: 2024-05-30
Add args to docker service ContainerSpec (#39464)
Add support to define Resources on DockerSwarmOperator (#39027)
Faster 'airflow_version' imports (#39552)
Simplify 'airflow_version' imports (#39497)
Limit requests in botocore upgrade test (#39747)
Pin requests due to incompatibility with docker-py (#39740)
Add args to docker service ContainerSpec (#39464)
Add support to define Resources on DockerSwarmOperator (#39027)
Faster 'airflow_version' imports (#39552)
Simplify 'airflow_version' imports (#39497)
Limit requests in botocore upgrade test (#39747)
Pin requests due to incompatibility with docker-py (#39740)
Nothing published for this version
This release of provider is only available for Airflow 2.7+ as explained in the Apache Airflow providers support policy .
Release Date: 2024-05-06
Note
This release of provider is only available for Airflow 2.7+ as explained in the Apache Airflow providers support policy .
Bump minimum Airflow version in providers to Airflow 2.7.0 (#39240)
Nothing published for this version
- Fix deprecated 'DockerOperator' operator arguments in 'MappedOperator'
Release Date: 2024-04-13
Note
The standard DOCKER_HOST environment variable now overrides the default value of the docker_url parameter when set. If DOCKER_HOST is set but you want to use the previous default value, then you must explicitly set docker_url="unix://var/run/docker.sock" in the DockerOperator constructor or @task.docker decorator.
Improve 'DockerOperator' to support multiple Docker hosts (#38466)
Fix deprecated 'DockerOperator' operator arguments in 'MappedOperator' (#38379)
Remove redundant compatibility usage of importlib_metadata (#38368)
DockerOperator: use DOCKER_HOST as default for docker_url (#38387)
Note
The standard DOCKER_HOST environment variable now overrides the default value of the docker_url parameter when set. If DOCKER_HOST is set but you want to use the previous default value, then you must explicitly set docker_url="unix://var/run/docker.sock" in the DockerOperator constructor or @task.docker decorator.
Improve 'DockerOperator' to support multiple Docker hosts (#38466)
Fix deprecated 'DockerOperator' operator arguments in 'MappedOperator' (#38379)
Remove redundant compatibility usage of importlib_metadata (#38368)
DockerOperator: use DOCKER_HOST as default for docker_url (#38387)
Nothing published for this version
Nothing published for this version
- Fix construct 'docker.TLSConfig' for 'docker>=7'
Release Date: 2024-03-08
Fix construct 'docker.TLSConfig' for 'docker>=7' (#37481)
Nothing published for this version
- Allow DockerOperator.skip_on_exit_code to be zero
Release Date: 2023-12-27
Allow DockerOperator.skip_on_exit_code to be zero (#36360)
Remove remaining Airflow 2.5 backcompat code from Docker Provider (#36325)
Allow DockerOperator.skip_on_exit_code to be zero (#36360)
Remove remaining Airflow 2.5 backcompat code from Docker Provider (#36325)
Nothing published for this version
This release of provider is only available for Airflow 2.6+ as explained in the Apache Airflow providers support policy .
Release Date: 2023-12-17
Note
This release of provider is only available for Airflow 2.6+ as explained in the Apache Airflow providers support policy .
Fix 'enable_logging=True' not working in 'DockerSwarmOperator' (#35677)
Fix broken log streaming from #35677 (#36127)
Bump minimum Airflow version in providers to Airflow 2.6.0 (#36017)
Follow BaseHook connection fields method signature in child classes (#36086)
Note
This release of provider is only available for Airflow 2.6+ as explained in the Apache Airflow providers support policy.
Fix 'enable_logging=True' not working in 'DockerSwarmOperator' (#35677)
Fix broken log streaming from #35677 (#36127)
Bump minimum Airflow version in providers to Airflow 2.6.0 (#36017)
Follow BaseHook connection fields method signature in child classes (#36086)
Nothing published for this version
Nothing published for this version
- Refactor docker operator attribute validations and docs
Release Date: 2023-11-29
Refactor docker operator attribute validations and docs (#35571)
Refactor docker operator attribute validations and docs (#35571)
Nothing published for this version
- fix '_DockerDecoratedOperator' module type attribute pickle error
Release Date: 2023-11-12
fix '_DockerDecoratedOperator' module type attribute pickle error (#35293)
fix '_DockerDecoratedOperator' module type attribute pickle error (#35293)
Nothing published for this version
- Deprecate get_hook method in DockerOperator
Release Date: 2023-10-17
Note
This release of provider is only available for Airflow 2.5+ as explained in the Apache Airflow providers support policy .
Add ulimits parameter to DockerOperator (#34284)
Bump min airflow version of providers (#34728)
Deprecate get_hook method in DockerOperator (#34432)
Note
This release of provider is only available for Airflow 2.5+ as explained in the Apache Airflow providers support policy.
Add ulimits parameter to DockerOperator (#34284)
Bump min airflow version of providers (#34728)
Deprecate get_hook method in DockerOperator (#34432)
Nothing published for this version
- Cleanup Docker operator logging
Release Date: 2023-09-12
Cleanup Docker operator logging (#33914)
Replace sequence concatenation by unpacking in Airflow providers (#33933)
Use literal dict instead of calling dict() in providers (#33761)
Replace type func by isinstance in DockerOperator (#33759)
Nothing published for this version
- Refactor: Improve detection of duplicates and list sorting
Release Date: 2023-08-29
Refactor: Improve detection of duplicates and list sorting (#33675)
Simplify conditions on len() in other providers (#33569)
Replace repr() with proper formatting (#33520)
Nothing published for this version
- Refactor: Simplify code in providers/docker
Release Date: 2023-08-14
Refactor: Simplify code in providers/docker (#33232)
Nothing published for this version
- Get rid of Python2 numeric relics
Release Date: 2023-08-08
Get rid of Python2 numeric relics (#33050)
Nothing published for this version
This release dropped support for Python 3.7
Release Date: 2023-06-23
Note
This release dropped support for Python 3.7
Remove Python 3.7 support (#30963)
Note
This release dropped support for Python 3.7
Remove Python 3.7 support (#30963)
Nothing published for this version
This release of provider is only available for Airflow 2.4+ as explained in the Apache Airflow providers support policy .
Release Date: 2023-05-22
Note
This release of provider is only available for Airflow 2.4+ as explained in the Apache Airflow providers support policy .
Bump minimum Airflow version in providers (#30917)
Note
This release of provider is only available for Airflow 2.4+ as explained in the Apache Airflow providers support policy.
Bump minimum Airflow version in providers (#30917)
Nothing published for this version
Nothing published for this version
- Deprecate 'skip_exit_code' in 'DockerOperator' and 'KubernetesPodOperator'
Release Date: 2023-04-24
Add multiple exit code handling in skip logic for 'DockerOperator' and 'KubernetesPodOperator' (#30769)
In 'DockerOperator', adding an attribute 'tls_verify' to choose whether to validate certificate (#30309) (#30310)
Deprecate 'skip_exit_code' in 'DockerOperator' and 'KubernetesPodOperator' (#30733)
Add multiple exit code handling in skip logic for 'DockerOperator' and 'KubernetesPodOperator' (#30769)
In 'DockerOperator', adding an attribute 'tls_verify' to choose whether to validate certificate (#30309) (#30310)
Deprecate 'skip_exit_code' in 'DockerOperator' and 'KubernetesPodOperator' (#30733)
Nothing published for this version
- fix template_fields in the decorator 'task.docker'
Release Date: 2023-02-21
fix template_fields in the decorator 'task.docker' (#29586)
Nothing published for this version
- Add correct widgets in Docker Hook
Release Date: 2023-01-26
Add correct widgets in Docker Hook (#28700)
Make docker operators always use 'DockerHook' for API calls (#28363)
Skip DockerOperator task when it returns a provided exit code (#28996)
Fix label name for 'reauth' field in Docker Connection (#28974)
Add correct widgets in Docker Hook (#28700)
Make docker operators always use 'DockerHook' for API calls (#28363)
Skip DockerOperator task when it returns a provided exit code (#28996)
Fix label name for 'reauth' field in Docker Connection (#28974)
Nothing published for this version
Nothing published for this version
- add hostname argument to DockerOperator
Release Date: 2023-01-05
add hostname argument to DockerOperator (#27822)
Move min airflow version down for Docker Provider to 2.3.0 (#28648)
Nothing published for this version
Nothing published for this version
airflow.logging_config.load_logging_config is deprecated (it now emits DeprecationWarning and delegates to new private helpers), and configure_logging…
📦 PyPI: https://pypi.org/project/apache-airflow/3.3.0/ 📚 Docs: https://airflow.apache.org/docs/apache-airflow/3.3.0/ 🛠 Release Notes: https://airflow.apache.org/docs/apache-airflow/3.3.0/release_notes.html 🐳 Docker Image: "docker pull apache/airflow:3.3.0" 🚏 Constraints: https://github.com/apache/airflow/tree/constraints-3.3.0
## Significant Changes
### Asset Partitioning (#64571, #65447, #66030, #66848, #67184, #67475, #67716, #68978)
Building on the asset partitioning introduced in 3.2.0, Airflow 3.3.0 substantially expands how a single upstream asset event fans out to partitioned downstream Dag runs. New partition mappers — RollupMapper (many-to-one), FanOutMapper (one-to-many), and FixedKeyMapper + SegmentWindow (categorical rollup) — compose with time windows (day/week/month/quarter/year) and a wait_policy (WaitForAll or MinimumCount(n)) to control when partitioned runs fire. Windows can fan out forward or backward in time, and total fan-out per upstream event is bounded by the new [scheduler] partition_mapper_max_downstream_keys config (configurable per mapper). Airflow 3.3.0 also adds the PartitionedAtRuntime timetable, which lets a Dag declare that its partition key(s) are assigned when the run starts rather than mapped from an upstream event.
For detailed usage instructions, see /authoring-and-scheduling/assets.
### Task and Asset State Store (#65759, #66073, #66160, #66463, #66586, #66859, #67041, #67292, #67319)
Airflow 3.3.0 introduces a first-class state store for tasks and assets (AIP-103). Tasks can persist arbitrary key-value state that survives across retries and runs via a new task_state_store accessor, and assets can carry their own state via asset_state_store — both available from the Task SDK. State is kept in the metadata database by default, or in a custom worker-side backend ([workers] state_store_backend), supports per-key retention with periodic garbage collection and an optional clear_on_success, and is fully manageable through the Core API and Execution API.
For detailed usage instructions, see /core-concepts/task-and-asset-state-store.
### Pluggable Retry Policies (#65474)
Task retry behaviour is now pluggable (AIP-105). In addition to a fixed retries count, you can attach a custom retry policy that decides whether and when a task is retried, enabling strategies such as retrying only on specific exceptions or backing off based on custom logic.
For detailed usage instructions, see concepts:retry-policies.
### Language Task SDK (Java and Go) (#65958, #67161, #67635, #67699)
Airflow 3.3.0 adds a Coordinator layer (AIP-108) that lets individual task implementations be written in non-Python languages while the Dag and its scheduling stay in Python. A task is declared in the Dag with @task.stub(queue=...); the worker routes it to a configured coordinator (JavaCoordinator for JVM languages, ExecutableCoordinator for self-contained native binaries such as Go) that runs the task in a language runtime and proxies Variables, Connections, and XComs back through the Execution API.
Warning
The Coordinator layer and the Java/Go SDKs are experimental in 3.3.0 and may change in future versions based on user feedback.
For detailed usage instructions, see /authoring-and-scheduling/language-sdks/index.
### Dag bundle version on clear, rerun, and backfill (#63884)
The new rerun_with_latest_version setting controls whether a cleared, rerun, or backfilled Dag run uses the latest bundle version or the original version from the initial run. The default is resolved by precedence: an explicit request parameter/CLI flag, then the Dag-level rerun_with_latest_version, then [core] rerun_with_latest_version, and finally False for clear/rerun and True for backfills (preserving historical behaviour). Airflow 2.x always reran with the latest code; 3.x introduced bundle versioning defaulting to the original version, and this setting gives users control.
See /administration-and-deployment/dag-bundles for full details.
### Provider example Dags as dedicated bundles (#66161)
Example Dags shipped by provider distributions are now discovered via ProvidersManager and registered as their own Dag bundles — one per provider, named apache-airflow-providers-<distribution>-example-dags (or <distribution>-example-dags for third-party providers). The [core] load_examples option still gates whether they are registered. REST API clients that filtered bundle_name by "dags-folder" for provider-shipped example Dags must update to the new per-provider bundle names; Dag identifiers are unchanged.
### Remote logging resolution decoupled from airflow.logging_config (#67056)
Remote task log handler resolution is now owned by the shared airflow_shared.logging.factory module and applies a single, well-defined precedence:
a user-defined [logging] logging_config_class exporting REMOTE_TASK_LOG / DEFAULT_REMOTE_CONN_ID (existing custom configs keep working);
ProvidersManager scheme dispatch — the scheme of [logging] remote_base_log_folder selects a provider RemoteLogIO class, instantiated via a no-argument from_config() classmethod;
a transitional legacy fallback reading airflow_local_settings.py (to be removed in Airflow 4.0).
airflow.logging_config.load_logging_config is deprecated (it now emits DeprecationWarning and delegates to new private helpers), and configure_logging no longer eagerly resolves the remote handler — resolution is lazy on first use. Providers that registered a remote-logging: block but do not implement from_config are skipped with a warning and fall through to the legacy path.
Migration: replace direct calls to airflow.logging_config.load_logging_config() with the new helpers, and have provider remote-log handler classes implement a no-argument from_config classmethod that reads airflow.providers.common.compat.sdk.conf.
### OpenTelemetry timer metrics now use Histogram (#64207)
OpenTelemetry timer and timing metrics are now recorded as Histograms instead of Gauges, preserving count, sum, and bucket distribution across recordings.
### Dag-processing "seconds ago" metric is now tagged (#62487)
dag_processing.last_run.seconds_ago.{dag_file} is now a legacy metric. The new dag_processing.last_run.seconds_ago is emitted with file_path, bundle_name and file_name tags (file_path + bundle_name uniquely identify the Dag file). The legacy metric is still emitted by default and can be disabled via [metrics] legacy_names_on.
### New Deadlines page under Browse (#67586)
A new Deadlines page is available under the Browse menu, accessible to any role that already has can_read and menu_access on Dag Runs.
## New Features
Add partition clear support to the REST API matching the CLI, with a clearPartitions endpoint and partition_key/partition_date window selectors on clearDagRuns (#68702)
Add [core] mp_start_method and [core] mp_forkserver_preload configuration options (which can be overridden per [scheduler]/[triggerer]/[dag_processor]) to control the multiprocessing start method (#68875)
Add a durable toggle to ResumableJobMixin to opt out of resumable execution (#68623)
Add a @result decorator to mark a TaskFlow task as the Dag's result task (#64563)
Add [triggerer] shared_stream_cohort_grace_period to reduce missed events on triggerer restart (#68888)
Propagate partition_date from producer Dag runs to consumers of partitioned assets (#67285)
Make the task and asset state store accessible from triggers via AssetStateStoreAccessors (#67839)
Add OpenTelemetry head sampling support (#68591)
Add async XCom accessors for async tasks (#68299)
Add an async aget_hook method to BaseHook for async tasks (#68506)
Allow custom partition Window subclasses via a plugin registry (#68717)
Support an extra field for the Coordinator (#68694)
Apply rerun_with_latest_version to TriggerDagRunOperator reruns (#67273)
Scope the XCom Execution API to teams in multi-team mode (#68850)
Enforce pool team ownership in the scheduling loop (#68649)
UI: Add team name to the asset graph view (#68457)
Populate partition_date for partitioned Dag runs whose composite asset key has a single time-based dimension (#68442)
UI: Add a column to the asset store table linking to the task instance that wrote it (#68395)
UI: Add a custom expiration datetime picker for the task store modal (#68394)
UI: Add additional task instance attributes to the task instance details section (#68378)
UI: Add a Details tab to the mapped task instance view (#68340)
UI: Add bulk marking of Dag runs as success or failed from multi-select (#68278)
Add --team-name support to the pool CLI commands (#68110)
UI: Add a full-screen toggle to the code viewer (#68044)
Add API endpoint support for consumer team asset filtering (#68034)
UI: Add bulk clear selection for task instances (#68029)
Add awaiting_input task state for Human-in-the-Loop, running off the triggerer (#68028)
Add bulk API to mark Dag runs as success or failed (#67948)
Record writer info for every asset store write for better cross-linkage (#67902)
Register XCom output_type classes from a worker-side Dag walk (#67875)
Add FixedKeyMapper and SegmentWindow for categorical asset-partition rollup (#67716)
Add a bulk POST /dags/{dag_id}/clearDagRuns API endpoint (#67709)
Return Pydantic model instances through XCom for structured output (#67644)
Add the ability to apply a note when clearing a Dag run or task instances (#67639)
Add consumer_teams to AssetAccessControl in the Task SDK (#67625)
Populate trigger team_name at creation time for multi-team support (#67605)
UI: Add bulk Clear on the Dag Runs list page (#67564)
Add multi-team query filtering to triggerer trigger assignment (#67517)
Add forward fan-out support via the forward kwarg on Window (AIP-76) (#67475)
Add patch task state API and expires_at support in the set API (AIP-103) (#67319)
Add a team_name column to the trigger table for multi-team triggerer support (#67305)
UI: Add asset and task store views (#67292)
Add a --team-name CLI argument to the triggerer for multi-team (#67254)
Add an allow_global option to asset access control (#67251)
Add mTLS and private CA support to the API client and server (#67214)
Add Markdown documentation support for TaskGroups (#67207)
Add a per-mapper max_fan_out override for partition fan-out cap (#67184)
Add timezone support to the SDK temporal partition mappers (#67164)
Add ResumableJobMixin with SparkSubmitOperator for surviving worker failures (#67118)
Add bulk delete for Dag runs (#67095)
Add a nav_top_level option for plugin nav items (#67084)
Add Core API endpoints for task state and asset state (AIP-103) (#67041)
Replace allow_producer_teams with access_control on Asset (#66954)
Add worker-side custom state backend support (AIP-103) (#66859)
Let partitioned Dag runs fire on a partial upstream window with wait_policy (#66848)
Consume task-emitted partition keys on asset events (AIP-76) (#66782)
Add per-task state key retention from operators (AIP-103) (#66699)
Add a callback_execution_timeout config for deadline callbacks (#66609)
Add a clear_on_success config to wipe task state on success (AIP-103) (#66586)
Add a partitions clear CLI command to reset DagRun partition fields (#66520)
Make CORS allow_credentials configurable (#66503)
Add periodic task state garbage collection and retention support (AIP-103) (#66463)
Add URI sanitizers and asset factories for new schemes (#66426)
Add a teams sync CLI command (#66418)
Add remote log upload support for callback subprocesses (#66379)
Add by-name/by-uri asset state routes and AssetUriRef support (AIP-103) (#66336)
UI: Add support for rendering multi-type params (#66278)
Filter Dags by teams when registering asset changes (#66168)
Wire up Task SDK communication and context access for task/asset state (AIP-103) (#66160)
UI: Add marking a task group as success or failed (#66146)
Add Execution API endpoints for task and asset states (AIP-103) (#66073)
Add FanOutMapper for one-to-many partition fan-out (#66030)
Add Variable.keys() to list variable keys by prefix in the Task SDK (#66022)
Add an airflow dags clear command for partition-range reprocessing (#66004)
Add a memray_detailed_tracing option for deeper memory profiling (#65996)
UI: Add support for different graph directions in the asset graph view (#65948)
UI: Add a Clear All Mapped Tasks button (#65813)
Add allow_producer_teams to the Asset SDK class (#65790)
UI: Show expected duration based on historical average in Dag Run details (#65722)
Add team name to the task context (#65617)
Add an on_kill() hook to BaseTrigger to handle user actions on triggers (#65590)
Allow accessing a Dag's members via [] (#65586)
Add pluggable retry policies for Airflow tasks (AIP-105) (#65474)
Add support for format="Duration" in params (#65469)
UI: Add pagination to the grid view (#65388)
Add partition_key to the task context (#65359)
Make the blocked-thread warning threshold configurable (#65009)
Add name fields to SDK deadline alerts (#64926)
Add dynamic interval resolution support via Variables for deadline alerts (#64751)
Add an is_backfillable property to Dag API responses (#64644)
Return dag-specified results in the dag run wait API (#64577)
Hold a Dag run until all upstream partitions arrive (AIP-76) (#64571)
Add a way to mark a return-value XCom as the dag result (#64522)
Allow accessing a TaskGroup's members via [] (#64430)
UI: Redo the Gantt chart (#64335)
UI: Add task-level filters to the Dag graph tab (#64271)
UI: Add bulk Clear, Mark Success/Fail, and delete for multiple task instances (#64141)
Check that multi-team is enabled when a team name is provided to the API (#63994)
Add a DagRunType for operators (#63733)
UI: Add search functionality to the task log viewer (#63467)
Add patching of task group instances in the API (#62812)
Add deadlines API endpoints (#62583)
Add async connection testing via workers for security isolation (#62343)
Add run_after to TriggerDagRunOperator (#62259)
UI: Display deadlines on the Dag Run and Overview tabs (#62195)
Re-enable the start_from_trigger feature with template-field rendering (#55068)
Backfill partitioned Dags by partition-date range (#67537)
Add a producer-side acknowledgement channel to shared-stream triggers (#67523)
UI: Add partition_date to the Dag run detail page (#68977)
Expose the upstream partition_key on triggering_asset_events and dag_run.consumed_asset_events (AIP-76) (#69120)
Allow get/set/delete/clear of AssetStateStoreAccessor to run on the triggerer (#68966)
## Bug Fixes
Fix KubernetesExecutor scheduler crash caused by a pod_override that cannot be pickled when running in-cluster (#68831)
UI: Fix dashboard alert clamping and collapse controls (#68893)
Stabilize mapped-task XCom result ordering in the Dag run wait endpoint by ordering on task_id/map_index (#68550)
Only log task state cleanup when a worker state store backend is configured (#68878)
Fix in-process Execution API loop stopped while transport still in use (#68865)
Fix task state store custom expiry datetime missing timezone on save (#68823)
Do not leak threads from InProcessExecutionAPI (#68840)
Fix partitioned backfill widening a sub-day window to the whole day (#68718)
UI: Fix inconsistent padding between Dag Runs and Task Instances list views (#68689)
Skip asset-change registration for tasks with no outlets (#68687)
Percent-encode API client path params for keys with slashes (#68667)
Fix bulk create+overwrite silently resetting unset fields on pools and connections (#68645)
Fix triggerer crash when a trigger subclass does not call super().__init__() (#68636)
Fix Task SDK swallowing errors when Variable.set() or Variable.delete() fails (#68542)
Populate partition_date when manually triggering partitioned Dags (#68458)
Improve warning visibility for invalid JSON when editing variables (#68268)
Fix the triggerer log server port configuration key (#67785)
Enforce ti:self scope on /execution/task-reschedules/{ti}/start_date (#67628)
UI: Fix misleading Calendar "Total Runs" coloring behavior (#67595)
Fix Stats not being initialized in the API server lifespan (#68514)
Fix BackfillDagRun.partition_key type annotation (#68432)
Fix backward compatibility for DagRunInfo partition fields (#68342)
Fix airflow db clean failing on foreign-key-referenced dag_version rows (#68339)
Fix 500 error when listing event logs with a NULL timestamp (#68338)
Fix MySQL downgrade from 3.3.0 for the deadline_alert.interval JSON conversion (#68337)
Fix older and custom secrets backends breaking on Airflow 3.2 (#68302)
Fix secrets backend connection errors being silently swallowed at DEBUG level (#68301)
UI: Fix the instance name title shown on non-Dag pages (#68288)
Fix scheduler not populating partition_date for temporal asset partitions (#68266)
UI: Fix wrong language being auto-detected from browser preferences (#68258)
Honor retry_policy on non-deferrable TriggerDagRunOperator wait failures (#68254)
Fix scheduler crash loop when the last task instance predates Dag versioning (#68253)
Fix team consumer asset filtering (#68242)
UI: Fix sluggish multi-selection behavior in tables (#68229)
UI: Fix mapped task instance links for tasks without a start date (#68194)
Fix setup/teardown auto-inclusion when clearing or marking tasks (#68193)
UI: Remove redundant columns from the XCom panel on the task instance page (#68188)
UI: Fix Gantt tooltip showing the wrong start date on queued/scheduled segments (#68176)
Fix Java SDK coordinator rejecting IPv4-mapped IPv6 connections (#68169)
Fix Java SDK tasks being rejected by the coordinator connection-ownership check (#68147)
UI: Fix language key for the Dag bundle filter (#68131)
Fix DagFileProcessorManager silent hang on database lock contention (#68118)
Mask all connection extra and variable values in the API audit log (#68049)
Fix spurious "Failed to detach context" error on Execution API disconnects (#68039)
UI: Fix Dag code highlighting for triple-quoted and escaped-brace f-strings (#68026)
Fix cursor encoding for column-form sort parameters in the REST API (#67973)
Fix SimpleAuthManager not preserving the deep-link next URL on first login (#67965)
Guard the task stats emission to prevent errors (#67955)
UI: Fix task instance state badge staying stale after a Mark-as action (#67950)
Register nested Pydantic models for XCom deserialization (#67932)
Fix example_asset_store consumer crash (#67922)
Raise InvalidJwtError in JWTValidator.avalidated_claims() when the key ID does not match (#67909)
Fix Kubernetes executor pod_override being stringified without the cncf provider (#67895)
UI: Prevent duplicate task instance summary stream refreshes after mutations (#67892)
Reject negative default_retention_days in the Task SDK and core API routes (#67890)
Fix none_failed_min_one_success trigger rule checks (#67873)
Remove trigger kwargs from the REST API response (#67868)
UI: Fix long parameter names overflowing the Trigger Dag modal (#67859)
Fix misleading log message in the task runner clear-on-success block (#67836)
Fix scheduler crash when logging orphaned task resets (#67822)
UI: Fix dashboard pool summary showing incorrect deferred slot usage (#67818)
Fix trigger datetime deserialization (#67795)
UI: Fix Graph layout for TaskGroup tasks wired to external nodes (#67720)
Fix airflow dags clear clearing the wrong day for non-UTC partitioned timetables (#67717)
Fix per-index evaluation of ONE_FAILED in mapped task groups (#67684)
UI: Fix dialog dismissal for the Chakra upgrade (#67674)
UI: Hide dashboard metric percentages when a state count is capped (#67664)
Apply per-file authorization to the dag-source endpoint (#67662)
Fix airflow dags next-execution --table crash when no next run exists (#67642)
UI: Fix the time picker omitting seconds (#67636)
Filter scheduling-dependencies graph edges by readable-Dag access (#67627)
Mask per-key secrets-backend-kwarg overrides on the Config API (#67622)
Fix GET /auth/login missing a 400 response in the OpenAPI spec (#67571)
Fix GET /pools incorrectly documenting a 404 response in the OpenAPI spec (#67570)
Add a compatibility layer for import errors caused by AirflowSecretsBackendAccessDenied (#67560)
UI: Fix rendering of None child state (#67552)
Fix sort order for mapped task instances (#67551)
Fix import errors total-entries count with multiple Dags per file (#67550)
UI: Prefer active over queued state for collapsed groups (#67543)
Fix callback state not updating from executor events due to a UUID type mismatch (#67542)
Reject wildcard origin in CORS config instead of toggling credentials (#67502)
Guard the finally-block logger in the HTTP access log middleware (#67501)
Strip CR/LF from user-supplied logical date before logging (#67500)
Redact secret-looking query parameters in the HTTP access log (#67498)
UI: Fix Calendar view to respect the user-selected timezone (#67497)
Escape LIKE wildcards in non-search filter parameters (#67496)
Fix missing redaction of secret values in variable JSON (#67495)
Fix bulk CREATE+OVERWRITE team-context authorization bypass (#67493)
UI: Return 400 instead of 500 from structure_data on a malformed asset expression (#67489)
Fix SimpleAuthManager redirect to the next URL after login (#67483)
Return 400 instead of 500 from materialize_asset on invalid input (#67445)
UI: Restore the Monaco find widget in the Dag Code view (#67391)
UI: Fix an HTTPException import that turned a 400 into a 500 in the dags endpoint (#67363)
Restore fail_fast handling when reschedule exceeds the MySQL TIMESTAMP limit (#67353)
Fix the Triggered Dag button not being visible during queued/running state (#67327)
Fix variables import with structured falsy values (#67060)
Avoid logging Execution API bearer credentials (#67059)
Sanitize Dag processor metric file names (#67029)
Return a 422 when the database rejects an API payload (#66888)
Prevent AlreadyRunningBackfill error caused by an invalid date range request (#66874)
Restrict owner-link and extra-link href values to safe schemes (http, https, mailto, relative) (#66741)
Add a session parameter to the BaseStateBackend interface to fix custom backends (#66708)
Allow deadline callbacks within the same Dag module (#66702)
UI: Fix relative React plugin bundle URLs in dev mode (#66618)
Validate Dag trigger conf as a JSON object or null (#66617)
Require a trust sentinel for state.user injection in get_user() (#66562)
Use hmac.compare_digest for SimpleAuthManager password comparison (CWE-208) (#66556)
Set SameSite=Lax on the SimpleAuthManager all-admins login cookie (#66502)
Reserve /auth and /pluginsv2 from plugin URL prefixes (#66501)
Use a cryptographically secure RNG for SimpleAuthManager passwords (#66500)
Fix Triggerer runner_health_check_threshold log formatting (#66486)
Fix Dag processor callback cleanup for versioned bundle files (#66484)
Default AIRFLOW_UID to 50000 in the airflow-init chown lines (#66481)
Strip CR/LF from MySQL URL query values before forwarding to my.cnf (#66325)
Fix CronMixin not resolving cron presets before validation (#66102)
Fix AirflowSDKConfigParser missing the mask_secrets method (#66077)
Fix resolve_xcom_backend to rely on the config schema default (#65938)
Fix a missing import cast error in the dag_run API route (#65748)
Mask Dag processor connection and variable responses (#65704)
UI: Show import error for deactivated Dags (#65687)
Forward MySQL SSL params from sql_alchemy_conn to airflow db shell (#65575)
Disable SQLite FK checks in the 0111 migration downgrade (#65545)
Handle Variable values that cannot be decrypted gracefully in the stable REST API (#65452)
Retry TriggerDagRunOperator when the triggered DagRun fails (#65390)
Fix task run exceptions never being caught by Sentry (#65161)
Fix the bulk task instance authorization error message rendering (#64719)
Fix trigger template rendering failure when operator template_fields differ from trigger attributes (#64715)
Fix task_defer with non-JSON next_kwargs in TaskInstance (#64714)
Add the error as context["exception"] in InProcessTestSupervisor (#64568)
Fix NPM security alerts in the simple auth manager (#64309)
Fix Dag run trigger to surface errors instead of swallowing them (#64130)
Fix Task SDK Connection extras built from a URI constructor (#64120)
Add insert/update-on-conflict for rendered task instance fields (#63874)
Fix timeout_with_traceback crashes on Windows and non-main threads (#63664)
UI: Wrap long lines in the rendered templates view (#63492)
Block path traversal via ".." in dag_id and run_id (#63296)
Fix the scheduler health check command in docker-compose.yaml (#62280)
Fix unmapped task deadlock when upstream tasks are removed (#62034)
Forward termination signals from the supervisor to the task subprocess (#61627)
Check destination team permission when using bulk APIs for connections, variables, and pools (#68573)
Fix the execution API /health check failing on the empty-path route (#68578)
Fix Dag run partition key filter breaking on composite keys containing | (#68459)
Fix the partition clear date range for non-UTC partitioned timetables (#68460)
Validate that partition keys are non-empty and within the column length (#68443)
Fix the scheduler serving stale Dag code after an in-place serialized Dag version update (#68558)
Determine the latest Dag version by version number to avoid collisions when timestamps tie (#68389)
Fix new runs and reruns executing an outdated bundle version when the Dag serialization is unchanged (#68336)
Fix remote logging from the task supervisor (#68370)
Upload task logs even when the final state update fails (#67935)
Escape URLs in the Task SDK client when looking up Dag operations (#68129)
Fix task scheduling when multi-team is enabled (#68634)
Fix secret values not being masked in rendered templates when keys use dot or dash separators (#68624)
Fix jwt_audience for the public API being read from two different config sections (#67494)
Fix duplicate deadline-miss callbacks firing from multiple HA scheduler replicas (#64737)
Fix scheduler crash on non-ASCII Dag names when OpenTelemetry metrics are enabled (#68023)
Fix Dag processor crash on non-ASCII names in OpenTelemetry gauge and timer metrics (#68284)
Report duplicate plugin names as import errors instead of silently ignoring them (#66649)
Require edit permission for async connection tests that update an existing connection (#68127)
Restore the deprecated [core] execution_api_server_url mapping to [workers] execution_api_server_url (#63949)
Fix dag.test() not re-syncing sibling Dags across repeated calls (#66205)
UI: Invalidate per-attempt task instance caches after actions so logs and details are not stale (#67212)
Fix task runner failure on a duplicate task instance success-state update (#63355)
Fix a race condition on the order_by parameter when listing Dag runs via the REST API (#68948)
Exclude non-successful Dag runs from the DeadlineReference.AVERAGE_RUNTIME deadline calculation so failed runs no longer skew the computed deadline (#68949)
Allow InProcessExecutionAPI to start without api_auth.jwt_secret configured (#68982)
Make airflow dags test wait for Human-in-the-loop input instead of looping indefinitely on parked HITL tasks (#69104)
Fix the Java coordinator rejecting macOS dual-stack loopback connections (#68973)
Fix an asset-event ingestion crash for Dags using FixedKeyMapper (#69326)
UI: Fix the details panel header overlapping the tabs (#69318)
Fix new Dag versions being created when a task's retry_policy was serialized (#69315)
Fix retry-policy overrides not being persisted to task-instance history (#69241)
Fix deadline callback data not being persisted (#69259)
## Miscellaneous
Propagate the resolved task log level and [logging] namespace_levels to language SDK runtimes (#68712)
Forward run-identity attributes (dag_id, run_id, run_type) to the trace sampler so a custom head sampler can differentiate by run kind (#68592)
Remove all_map_indices from task_state_store.clear() in the task context (#68880)
Optimize the dag processor by caching bundle-to-team name lookups (#68730)
Rename the misleading last_automated_run param to reference_run (#68714)
Add a team_name tag to the remaining multi-team metrics (#68601)
Add a team_name tag to dag processor metrics for multi-team deployments (#68599)
Add a team_name tag to asset metrics for multi-team deployments (#68367)
UI: Persist dashboard alert collapse state and clamp long alerts (#68329)
Optimize bulk variable deletion to avoid N+1 queries (#68508)
UI: Unify the Dag Code tab toolbar styling with the Logs toolbar (#68449)
Optimize bulk Dag run authorization to avoid N+1 team-name queries (#68286)
Improve airflow dags command to use bulk clear (#68280)
Add the task_state_store table to the airflow db clean mechanism (#68218)
Add metrics and traces to ResumableJobMixin for crash recovery (#68213)
Improve ResumableJobMixin crash-recovery observability with better logging (#68206)
Pass DagRun to task_instance_mutation_hook for run-aware task mutation (#68198)
Add team_name to multi-team metrics (#68108)
Reduce redundant Dag team lookups in authorization checks (#68020)
Enhance ResumableJobMixin.get_job_status with context for better job status tracking (#68009)
Propagate OpenTelemetry trace headers from the client to Execution API server-side spans (#67904)
Widen the type hint for the DagRun.get_task_instances / fetch_task_instances state parameter (#67880)
UI: Use the bulk clear Dag runs endpoint for bulk Dag run clear (#67846)
Add a default parameter to the task and asset state get() method (#67842)
Make core API routes for task and asset states interact only with the database (#67835)
Optimize Dag processor file-queue deduplication from O(N^2) to O(N) (#67750)
Add allow_consumer_teams and allow_global_consumers columns to TaskOutletAssetReference (#67730)
Speed up the Dags list and dashboard queries on large DagRun tables (#67721)
Make partition_key provenance-only and inherit it onto asset events (#67718)
Speed up Dag serialization by skipping a redundant asset roundtrip (#67702)
Cache BaseOperator.__init__ signature in operator serialization (#67701)
Optimize TaskGroup.topological_sort for reverse-declared Dags (#67688)
Update serialization for producer-side asset access control (#67658)
Allow outlets to be added and accessed in AssetStateAccessor (#67619)
Unify task/asset state storage between the Core API and Execution API (#67547)
Decorate custom state references with an envelope for UI clarity (#67530)
Simplify authoring of task and asset states by allowing JSON types (#67418)
Replace Sphinx Redoc with Swagger for the API docs (#67390)
Emit OpenTelemetry spans around listener hook calls (#67347)
UI: Update verbiage for lower-priority backfill runs (#67338)
Fix N+1 query in the bulk task instance delete endpoint (#67304)
Speed up TaskGroup.topological_sort with an int-indexed projected sweep (#67288)
UI: Use react-query native error state for bulk action hooks (#67284)
Wrap executor.heartbeat() in a timer to localize scheduler loop slowdowns (#66808)
Emit dagrun.first_task_start_delay separately from scheduling delay (#66807)
Share one poll loop across sibling event triggers (#66584)
UI: Upgrade icons, spacing, and default component themes (#66569)
Warn when SimpleAuthManager runs in a production-shaped deployment (#66563)
Migrate Stackdriver logging config to the RemoteLogIO pattern (#66513)
Add a BundleVersion dataclass and version_data persistence to DagVersion (#66491)
Avoid lazy-loading timetable fields for latest DagRuns (#66488)
Move allow_producer_teams to DagScheduleAssetReference (#66487)
Pass user teams to the create_asset_event endpoint (#66367)
Load USFederalHolidayCalendar lazily to reduce memory usage when loading examples (#66303)
Propagate task OpenTelemetry trace context through IPC into Execution API requests (#66151)
Surface worker Dag parse duration in the task log (#66138)
Skip deserializing trigger_kwargs when loading serialized Dags (#66002)
Honor AUTH_ROLE_PUBLIC in the FastAPI API server (#65685)
Add extended sysinfo for the Edge worker (#65472)
Clarify logs when a Dag is being processed in the Dag processor (#65196)
Add indexes on task_instance.dag_version_id and dag_run.created_dag_version_id (#64818)
Improve creation of RuntimeTaskInstance in TriggerRunner for start_for_trigger functionality (#64298)
Mark the Triggerer supervisor as a server context so it can read metastore connections (#64022)
Load hook metadata from YAML without importing the hook class (#63826)
Add detailed task spans (#63568)
Downgrade logging on query JSON parsing and add a JSON load condition (#62044)
UI: Add a Deadlines section with a time-range selector to the Dashboard page (#68038)
UI: Add a modal for editing notes with Markdown support (#68362)
UI: Improve the Human-In-The-Loop form UX (#68397)
Add a team_name tag to executor metrics for multi-team deployments (#68593)
Make task and asset state store row size limits configurable (#68133)
UI: Add notification UX for Human-In-The-Loop actions (#68346)
Allow synchronous deadline callbacks (SyncCallback) to access Connections and Variables (#65269)
Add a team_name tag to deadline metrics for multi-team deployments (#68589)
Add a team_name tag to scheduler metrics for multi-team deployments (#68594)
Defer the Cadwyn import so FastAPI/Starlette stay off the Task SDK worker path, reducing per-worker memory (#69029)
## Doc Only Changes
Complete the Taiwanese Mandarin (zh-TW) translation (#68870)
Add missing Korean (ko) translations (#68600)
Close German (de) translation gaps (#68356)
Add a segment fan-out example to the asset partition example Dag (#68722)
Fix runtime-partition example Dags using unreachable schedules (#68719)
Add an example Dag for the task state store with mapped tasks (#68670)
Fix the gap in the Taiwanese Mandarin (zh-TW) translation (#68668)
Add wait-policy examples to the asset partition example Dag (#68658)
Add a contributing guide for language SDKs (#68330)
Add sdk.TIRunContext documentation for the Go SDK (#68319)
Add a Go Task SDK authoring guide to the docs (#68223)
Update supported-versions doc to mark 2.11.2 as EOL (#68212)
Add documentation for ResumableJobMixin and resumable tasks (#68136)
Add CLI examples for team-scoped pools (#68111)
Add docs for multi-team triggerer support (#67608)
Clarify trigger rule behavior for the removed upstream state (#67452)
Fix outdated image links in dags.rst (#67357)
Add an example and docs for runtime asset partitioning (AIP-76) (#67307)
Add documentation for the Task and Asset Store (AIP-103) (#67299)
Add a dynamic task mapping no-op example (#67022)
Add documentation about adding access_control to the Asset object (#66949)
Add a how-to for Dag-level retry via on_failure_callback (#66277)
Fix documentation after PR 62645 (#65843)
Add documentation for team-based asset event filtering (#65690)
Document on_kill()/cleanup() for triggers (#65671)
Explain xcom_pull behaviour without task_ids in the docs (#65406)
Improve standalone authentication documentation for Airflow 3.x (#65330)
Clarify manual Dag run data interval semantics in Airflow 3 (#64740)
Document and test xcom_pull run_id usage for triggered Dag runs (#63030)
Update params in the backfill documentation (#61821)
Document the apache-airflow-mypy package in the core docs (#68561)
Fix typos and formatting in the Fundamentals documentation (#68524)
Complete the Hindi (hi) UI translation (#68574)
Fill the Taiwanese Mandarin (zh-TW) UI translation gap (#68563)
Document that Dag bundle kwargs should reference a Connection rather than inline credentials (#69105)
Add example plugins and expand the asset-partitions documentation (#69017)
Java SDK docs: JUL setup, pinning java_executable, and a config-reload note (#69020)
Correct the example config for the coordinators (#68940)
Release Date: 2022-11-18
Note
This release of provider is only available for Airflow 2.3+ as explained in the Apache Airflow providers support policy .
Move min airflow version to 2.3.0 for all providers (#27196)
Add ipc_mode for DockerOperator (#27553)
Add env-file parameter to Docker Operator (#26951)
Note
This release of provider is only available for Airflow 2.3+ as explained in the Apache Airflow providers support policy.
Move min airflow version to 2.3.0 for all providers (#27196)
Add ipc_mode for DockerOperator (#27553)
Add env-file parameter to Docker Operator (#26951)
Nothing published for this version
FileLoadStat will no longer produce paths beginning with / with the meaning of "relative to the dags folder". This is a breaking change for any custom…
📦 PyPI: https://pypi.org/project/apache-airflow/3.2.0/ 📚 Docs: https://airflow.apache.org/docs/apache-airflow/3.2.0/ 🛠 Release Notes: https://airflow.apache.org/docs/apache-airflow/3.2.0/release_notes.html 🐳 Docker Image: "docker pull apache/airflow:3.2.0" 🚏 Constraints: https://github.com/apache/airflow/tree/constraints-3.2.0
## Significant Changes
### Asset Partitioning
The headline feature of Airflow 3.2.0 is asset partitioning — a major evolution of data-aware scheduling. Instead of triggering Dags based on an entire asset, you can now schedule downstream processing based on specific partitions of data. Only the relevant slice of data triggers downstream work, making pipeline orchestration far more efficient and precise.
This matters when working with partitioned data lakes — date-partitioned S3 paths, Hive table partitions, BigQuery table partitions, or any other partitioned data store. Previously, any update to an asset triggered all downstream Dags regardless of which partition changed. Now only the right work gets triggered at the right time.
For detailed usage instructions, see /authoring-and-scheduling/assets.
### Multi-Team Deployments
Airflow 3.2 introduces multi-team support, allowing organizations to run multiple isolated teams within a single Airflow deployment. Each team can have its own Dags, connections, variables, pools, and executors— enabling true resource and permission isolation without requiring separate Airflow instances per team.
This is particularly valuable for platform teams that serve multiple data engineering or data science teams from shared infrastructure, while maintaining strong boundaries between teams' resources and access.
For detailed usage instructions, see /core-concepts/multi-team.
Warning
Multi-Team Deployments are experimental in 3.2.0 and may change in future versions based on user feedback.
### Synchronous callback support for Deadline Alerts
Deadline Alerts now support synchronous callbacks via SyncCallback in addition to the existing asynchronous AsyncCallback. Synchronous callbacks are executed by the executor (rather than the triggerer), and can optionally target a specific executor via the executor parameter.
A Dag can also define multiple Deadline Alerts by passing a list to the deadline parameter, and each alert can use either callback type.
Warning
Deadline Alerts are experimental in 3.2.0 and may change in future versions based on user feedback. Synchronous deadline callbacks (SyncCallback) do not currently support Connections stored in the Airflow metadata database.
For detailed usage instructions, see /howto/deadline-alerts.
### UI Enhancements & Performance
Grid View Virtualization: The Grid view now uses virtualization -- only visible rows are rendered to the DOM. This dramatically improves performance when viewing Dags with large numbers of task runs, reducing render time and memory usage for complex Dags. (#60241)
XCom Management in the UI: You can now add, edit, and delete XCom values directly from the Airflow UI. This makes it much easier to debug and manage XCom state during development and day-to-day operations without needing CLI commands. (#58921)
HITL Detail History: The Human-in-the-Loop approval interface now includes a full history view, letting operators and reviewers see the complete audit trail of approvals and rejections for any task. (#56760, #55952)
Gantt Chart Improvements:
All task tries displayed: Gantt chart now shows every attempt, not just the latest
Task display names in Gantt: task_display_name shown for better readability (#61438)
ISO dates in Gantt: Cross-browser consistent date format (#61250)
Fixed null datetime crash: Gantt chart no longer crashes on tasks with null datetime fields
### New --only-idle flag for the scheduler CLI
The airflow scheduler command has a new --only-idle flag that only counts runs when the scheduler is idle. This helps users run the scheduler once and process all triggered Dags and queued tasks. It requires and complements the --num-runs flag so one can set a small value instead of guessing how many iterations the scheduler needs.
### Replace per-run TI summary requests with a single NDJSON stream
The grid, graph, gantt, and task-detail views now fetch task-instance summaries through a single streaming HTTP request (GET /ui/grid/ti_summaries/{dag_id}?run_ids=...) instead of one request per run. The server emits one JSON line per run as soon as that run's task instances are ready, so columns appear progressively rather than all at once.
What changed:
GET /ui/grid/ti_summaries/{dag_id}?run_ids=... is now the sole endpoint for TI summaries, returning an application/x-ndjson stream where each line is a serialized GridTISummaries object for one run.
The old single-run endpoint GET /ui/grid/ti_summaries/{dag_id}/{run_id} has been removed.
The serialized Dag structure is loaded once and shared across all runs that share the same dag_version_id, avoiding redundant deserialization.
All UI views (grid, graph, gantt, task instance, mapped task instance, group task instance) use the stream endpoint, passing one or more run_ids.
### Structured JSON logging for all API server output
The new json_logs option under the [logging] section makes Airflow produce all its output as newline-delimited JSON (structured logs) instead of human-readable formatted logs. This covers the API server (gunicorn/uvicorn), including access logs, warnings, and unhandled exceptions.
Not all components support this yet — notably airflow celery worker but any non-JSON output when json_logs is enabled will be treated as a bug. (#63365)
### Remove legacy OTel Trace metaclass and shared tracer wrappers
The interfaces and functions located in airflow.traces were internal code that provided a standard way to manage spans in internal Airflow code. They were not intended as user-facing code and were never documented. They are no longer needed so we remove them in 3.2. (#63452)
### Move task-level exception imports into the Task SDK
Airflow now sources task-facing exceptions (AirflowSkipException, TaskDeferred, etc.) from airflow.sdk.exceptions. airflow.exceptions still exposes the same exceptions, but they are proxies that emit DeprecatedImportWarning so Dag authors can migrate before the shim is removed.
What changed:
Runtime code now consistently raises the SDK versions of task-level exceptions.
The Task SDK redefines these classes so workers no longer depend on airflow-core at runtime.
airflow.providers.common.compat.sdk centralizes compatibility imports for providers.
Behaviour changes:
Sensors and other helpers that validate user input now raise ValueError (instead of AirflowException) when poke_interval/ timeout arguments are invalid.
Importing deprecated exception names from airflow.exceptions logs a warning directing users to the SDK import path.
Exceptions now provided by ``airflow.sdk.exceptions``:
AirflowException and AirflowNotFoundException
AirflowRescheduleException and AirflowSensorTimeout
AirflowSkipException, AirflowFailException, AirflowTaskTimeout, AirflowTaskTerminated
TaskDeferred, TaskDeferralTimeout, TaskDeferralError
DagRunTriggerException and DownstreamTasksSkipped
AirflowDagCycleException and AirflowInactiveAssetInInletOrOutletException
ParamValidationError, DuplicateTaskIdFound, TaskAlreadyInTaskGroup, TaskNotFound, XComNotFound
AirflowOptionalProviderFeatureException
Backward compatibility:
Existing Dags/operators that still import from airflow.exceptions continue to work, though they log warnings.
Providers can rely on airflow.providers.common.compat.sdk to keep one import path that works across supported Airflow versions.
Migration:
Update custom operators, sensors, and extensions to import exception classes from airflow.sdk.exceptions (or from the provider compat shim).
Adjust custom validation code to expect ValueError for invalid sensor arguments if it previously caught AirflowException.
### Support numeric multiplier values for retry_exponential_backoff parameter
The retry_exponential_backoff parameter now accepts numeric values to specify custom exponential backoff multipliers for task retries. Previously, this parameter only accepted boolean values (True or False), with True using a hardcoded multiplier of 2.0.
New behavior:
Numeric values (e.g., 2.0, 3.5) directly specify the exponential backoff multiplier
retry_exponential_backoff=2.0 doubles the delay between each retry attempt
retry_exponential_backoff=0 or False disables exponential backoff (uses fixed retry_delay)
Backwards compatibility:
Existing Dags using boolean values continue to work:
retry_exponential_backoff=True → converted to 2.0 (maintains original behavior)
retry_exponential_backoff=False → converted to 0.0 (no exponential backoff)
API changes:
The REST API schema for retry_exponential_backoff has changed from type: boolean to type: number. API clients must use numeric values (boolean values will be rejected).
Migration:
While boolean values in Python Dags are automatically converted for backwards compatibility, we recommend updating to explicit numeric values for clarity:
Change retry_exponential_backoff=True → retry_exponential_backoff=2.0
Change retry_exponential_backoff=False → retry_exponential_backoff=0
### Move serialization/deserialization (serde) logic into Task SDK
Airflow now sources serde logic from airflow.sdk.serde instead of airflow.serialization.serde. Serializer modules have moved from airflow.serialization.serializers.* to airflow.sdk.serde.serializers.*. The old import paths still work but emit DeprecatedImportWarning to guide migration. The backward compatibility layer will be removed in Airflow 4.
What changed:
Serialization/deserialization code moved from airflow-core to task-sdk package
Serializer modules moved from airflow.serialization.serializers.* to airflow.sdk.serde.serializers.*
New serializers should be added to airflow.sdk.serde.serializers.* namespace
Code interface changes:
Import serializers from airflow.sdk.serde.serializers.* instead of airflow.serialization.serializers.*
Import serialization functions from airflow.sdk.serde instead of airflow.serialization.serde
Backward compatibility:
Existing serializers importing from airflow.serialization.serializers.* continue to work with deprecation warnings
All existing serializers (builtin, datetime, pandas, numpy, etc.) are available at the new location
Migration:
For existing custom serializers: Update imports to use airflow.sdk.serde.serializers.*
For new serializers: Add them to airflow.sdk.serde.serializers.* namespace (e.g., create task-sdk/src/airflow/sdk/serde/serializers/your_serializer.py)
### Methods removed from PriorityWeightStrategy
On (experimental) class PriorityWeightStrategy, functions serialize() and deserialize() were never used anywhere, and have been removed. They should not be relied on in user code. (#59780)
### Methods removed from TaskInstance
On class TaskInstance, functions run(), render_templates(), get_template_context(), and private members related to them have been removed. The class has been considered internal since 3.0, and should not be relied on in user code. (#59780, #59835)
### Modify the information returned by DagBag
New behavior:
DagBag now uses Path.relative_to for consistent cross-platform behavior.
FileLoadStat now has two additional nullable fields: bundle_path and bundle_name.
Backward compatibility:
FileLoadStat will no longer produce paths beginning with / with the meaning of "relative to the dags folder". This is a breaking change for any custom code that performs string-based path manipulations relying on this behavior. Users are advised to update such code to use pathlib.Path. (#59785)
### Remove --conn-id option from airflow connections list
The redundant --conn-id option has been removed from the airflow connections list CLI command. Use airflow connections get instead. (#59855)
### Add operator-level render_template_as_native_obj override
Operators can now override the Dag-level render_template_as_native_obj setting, enabling fine-grained control over whether templates are rendered as native Python types or strings on a per-task basis. Set render_template_as_native_obj=True or False on any operator to override the Dag setting, or leave as None (default) to inherit from the Dag.
### Add gunicorn support for API server with zero-downtime worker recycling
The API server now supports gunicorn as an alternative server with rolling worker restarts to prevent memory accumulation in long-running processes.
Key Benefits:
Rolling worker restarts: New workers spawn and pass health checks before old workers are killed, ensuring zero downtime during worker recycling.
Memory sharing: Gunicorn uses preload + fork, so workers share memory via copy-on-write. This significantly reduces total memory usage compared to uvicorn's multiprocess mode where each worker loads everything independently.
Correct FIFO signal handling: Gunicorn's SIGTTOU kills the oldest worker (FIFO), not the newest (LIFO), which is correct for rolling restarts.
Configuration:
[api]
# Use gunicorn instead of uvicorn
server_type = gunicorn
# Enable rolling worker restarts every 12 hours
worker_refresh_interval = 43200
# Restart workers one at a time
worker_refresh_batch_size = 1
Or via environment variables:
export AIRFLOW__API__SERVER_TYPE=gunicorn
export AIRFLOW__API__WORKER_REFRESH_INTERVAL=43200
Requirements:
Install the gunicorn extra: pip install 'apache-airflow-core[gunicorn]'
Note on uvicorn (default):
The default uvicorn mode does not support rolling worker restarts because:
With workers=1, there is no master process to send signals to
uvicorn's SIGTTOU kills the newest worker (LIFO), defeating rolling restart purposes
Each uvicorn worker loads everything independently with no memory sharing
If you need worker recycling or memory-efficient multi-worker deployment, use gunicorn. (#60921)
### Improved performance of rendered task instance fields cleanup for Dags with many mapped tasks (~42x faster)
The config max_num_rendered_ti_fields_per_task is renamed to num_dag_runs_to_retain_rendered_fields (old name still works with deprecation warning).
Retention is now based on the N most recent dag runs rather than N most recent task executions, which may result in fewer records retained for conditional/sparse tasks. (#60951)
### AuthManager Backfill permissions are now handled by the requires_access_dag on the DagAccessEntity.Run
is_authorized_backfill of the BaseAuthManager interface has been removed. Core will no longer call this method and their provider counterpart implementation will be marked as deprecated. Permissions for backfill operations are now checked against the DagAccessEntity.Run permission using the existing requires_access_dag decorator. In other words, if a user has permission to run a Dag, they can perform backfill operations on it.
Please update your security policies to ensure that users who need to perform backfill operations have the appropriate DagAccessEntity.Run permissions. (Users having the Backfill permissions without having the DagRun ones will no longer be able to perform backfill operations without any update)
### Python 3.14 support added
Airflow 3.2.0 adds support for Python 3.14. (#63787)
### Reduce API server memory by eliminating SerializedDAG loads on task start
The API server no longer loads the full SerializedDAG when starting tasks, significantly reducing memory usage. (#60803)
### Remove MySQL client from container images
MySQL client support has been removed from official Airflow container images. MySQL users building on official images must install the client themselves. (#57146)
### Add support for async callables in PythonOperator
The PythonOperator parameter python_callable now also supports async callables in Airflow 3.2, allowing users to run async def functions without manually managing an event loop. (#60268)
### Make start_date optional for @continuous schedule
The schedule="@continuous" parameter now works without requiring a start_date, and any Dags with this schedule will begin running immediately when unpaused. (#61405)
## New Features
Add FIPS support by making Python LTO configurable via PYTHON_LTO build argument (#58337)
Add support for task queue-based Trigger assignment to specific Triggerer hosts via the new --queues CLI option for the trigger command (#59239)
Add --show-values and --hide-sensitive flags to CLI connections list and variables list to hide sensitive values by default (#62344)
Add support for setting individual secrets backend kwargs via AIRFLOW__SECRETS__BACKEND_KWARG__<KEY> environment variables (#63312)
Add only_new parameter to Dag clear to only clear newly added task instances (#59764)
Add log_timestamp_format config option for customizing component log timestamps (#63321)
Add --action-on-existing-key option to pools import and connections import CLI commands (#62702)
Add back --use-migration-files flag for airflow db init (#62234)
Add AllowedKeyMapper for partition key validation in asset partitioning (#61931)
Add ChainMapper for chaining multiple partition mappers (#64094)
Add cryptographic signature verification for Python source packages in Docker builds (#63345)
Add Human-in-the-Loop (HITL) Review system for AgenticOperator (#63081)
Add @task.stub decorator to allow tasks in other languages to be defined in Dags (#56055)
Add support for creating connections using URI in SDK (#62211)
Add note support to TriggerDagRunOperator (#60810)
Add allowed_run_types to whitelist specific Dag run types (#61833)
Add OR operator support in API search parameters (#60008)
Add API filtering for Dags by timetable type (#58852)
Add wildcard support for dag_id and dag_run_id in bulk task instance endpoint (#57441)
Add operator_name_pattern, pool_pattern, queue_pattern as task instance search filters (#57571)
Add update_mask support for bulk PATCH APIs (#54597)
Add asset event emission listener event (#61718)
Add source parameter to Param (#58615)
Add lazy filtering for inlet events by time range, ordering, and limit (#54891)
Add ability to get previous TaskInstance on RuntimeTaskInstance (#59712)
Add required context messages to all DagRun state change notifications (#56272)
Add max_trigger_to_select_per_loop config for Triggerer HA setup (#58803)
Add uvicorn_logging_level config option to control API server access logs (#56062)
Add correlation-id support to Execution API for request tracing (#57458)
Add executor.running_dags gauge metric to expose count of running Dags (#52815)
Add submodules support to GitDagBundle (#59911)
Add HTTP URL authentication support to GitHook for Dag bundles (#58194)
Add stream method to RemoteIO for ObjectStorage (#54813)
Add CLI hot-reload support via --dev flag (#57741)
Add auth list-envs command to list CLI environments and auth status (#61426)
Add Dag bundles to airflow info command output (#59124)
Add new arguments to db_clean to explicitly include or exclude Dags (#56663)
UI: Add Jobs page to the Airflow UI (#61512)
UI: Add version change indicators for Dag and bundle versions in Grid view (#53216)
UI: Add segmented state bar for collapsed task groups and mapped tasks (#61854)
UI: Add date range filter for Dag executions (#60772)
UI: Add "Select Recent Configurations" to trigger form, restoring Airflow 2 functionality (#56406)
UI: Add copy button to logs (#61185)
UI: Add filename display to Dag Code tab for easier file identification (#60759)
UI: Add Dag run state filter to grid view options (#55898)
UI: Add task upstream/downstream filter to Graph and Grid views (#57237)
UI: Add filters to Task Instances tab (#56920)
UI: Add display of active Dag runs count in header with auto-refresh (#58332)
UI: Add Dag ID pattern search to Dag Runs and Task Instances pages (#55691)
UI: Add delete button for Dag runs in more options menu (#55696)
UI: Add depth filter to TaskStreamFilter (#60549)
UI: Add theme config support (#58411)
UI: Add support for globalCss in custom themes (#61161)
UI: Add display of logged-in user in settings button (#58981)
UI: Add tooltip for explaining task filter traversal (#61401)
UI: Add self-service JWT token generation for API and CLI access (#63195)
UI: Add bulk operations for edge workers page (#64033)
UI: Add real-time concurrency control for edge workers (#63142)
UI: Add run_after date filter on Dag runs page (#62797)
UI: Add bundle version filter on Dag runs page (#62810)
UI: Add icon support for theme customization (#62172)
UI: Add Monaco editor for all JSON editing fields (#62708)
UI: Add run type legend tooltip to grid view (#62946)
UI: Allow customizing gray, black, and white color tokens in AIRFLOW__API__THEME in addition to brand (#64232)
## Bug Fixes
Fix sensitive configuration values not being masked in public config APIs; treat the deprecated non-sensitive-only value as True (#59880)
Fix InvalidStatsNameException for pool names with invalid characters by auto-normalizing them when emitting metrics (#59938)
Fix JWT tokens appearing in task logs by excluding the token field from workload object representations (#62964)
Fix security iframe navigation when AIRFLOW__API__BASE_URL basename is configured (#63141)
Fix grid view URL for dynamic task groups producing 404 by not appending /mapped to group URLs (#63205)
Fix ti_skip_downstream overwriting RUNNING tasks to SKIPPED in HA deployments (#63266)
Fix duplicate task execution when running multiple schedulers (#60330)
Fix callback starvation across Dag bundles (#63795)
Fix @task decorator failing for tasks that return falsy values like 0 or empty string (#63788)
Fix LatestOnlyOperator not working when direct upstream of a dynamically mapped task (#62287)
Fix inconsistent XCom return type in mapped task groups with dynamic mapping (#59104)
Fix task group lookup using wrong Dag version for historical runs, causing 404 errors in grid view (#63360)
Fix import errors when updating Dags in other bundles (#63615)
Fix DagRun span emission crash when context_carrier is None (#64087)
Fix false error logs for partitioned timetables when next_dagrun fields are None (#63962)
Fix timetable serialization error when decoding relativedelta (#61671)
Fix task_instance_mutation_hook receiving run_id=None during TaskInstance creation (#63049)
Fix scheduler crash on None dag_version access (#62225)
Fix MetastoreBackend.expunge_all() corrupting shared session state (#63080)
Fix triggerer logger file descriptor closed prematurely when trigger is removed (#62103)
Fix airflowignore negation pattern handling for directory-only patterns (#62860)
Fix false warnings for TYPE_CHECKING-only forward references in TaskFlow decorators (#63053)
Fix structlog JSON serialization crash on non-serializable objects (#62656)
Fix backward compatibility for deadline alert serialization (#63701)
Fix queued_tasks type mismatch in hybrid executors (CeleryKubernetesExecutor, LocalKubernetesExecutor) (#63744)
Fix Celery tasks not being registered at worker startup (#63110)
Fix asset partition detection incorrectly identifying Dags as partitioned (#62864)
Fix pathlib.Path objects incorrectly resolved by Jinja templater in Task SDK (#63306)
Fix state mismatch in Kubernetes executor after pod completion (#63061)
Fix make_partial_model for API Pydantic models (#63716)
Fix WTForms validator compatibility in connection form (#63823)
Fix _execution_api_server_url() ignoring configured value and falling back to edge config (#63192)
Fix DetachedInstanceError for airflow tasks render command (#63916)
Fix scheduler isolating per-dag-run failures to prevent a single DagRun crashing all scheduling (#62893)
Fix task argument order in @task definition causing Dag parsing errors (#62174)
Fix limit parameter not sent in execute_list server requests (#63048)
Fix circular import from airflow.configuration causing ImportError on Python 3.14 (#63787)
Fix map_index range validation in CLI commands (#62626)
Fix nullable ORM fields by restoring correct defaults and dropping unreleased corrective migration (#63899)
Fix race condition in auth manager initialization on concurrent requests (#62431)
Fix FabAuthManager race condition on startup with multiple workers (#62737)
Fix FabAuthManager race condition when workers concurrently create permissions, roles, and resources (#63842)
Fix JWTValidator not handling GUESS algorithm with JWKS (#63115)
Fix FabAuthManager first idle MySQL disconnect in token auth (#62919)
Fix JWTBearerTIPathDep import errors in Human-In-The-Loop routes (#63277)
Fix 403 from roles endpoint despite admin rights in FAB provider (#64097)
Fix task log filters not working in full-screen mode (#62747)
Fix duplicate log reads when resuming from log_pos (#63531)
Fix 404 errors from worker log server for historical retry attempts now handled gracefully (#62475)
Fix Elasticsearch/OpenSearch logging exception details missing in task log tab (#63739)
Fix task-level audit logs missing success/running events (#61932)
Fix null dag_run_conf causing serialization error in BackfillResponse (#63259)
Fix CLI asset materialization using wrong Dag run type (#63815)
Fix migration 0094 performance: use SQL instead of Python deserialization (#63628)
Fix migration reliability: replace savepoints with per-Dag transactions (#63591)
Fix slow downgrade performance by adding index to deadline.callback_id (#63612)
Fix MySQL reserved keyword interval causing query failures in deadline_alert (#63494)
Fix MySQL serialize_dag query failure during deadline migration (#63804)
Fix SQLite downgrade failures caused by FK constraints during batch table recreation (#63437)
Fix migration 0096 downgrade failing when team table has existing rows (#63449)
Fix missing warning about hardcoded 24h visibility_timeout that kills long-running Celery tasks (#62869)
Fix scheduler memory issue by removing eager loading of all task instances (#60956)
Fix MySQL sort buffer overflow in deadline alert migration (#61806)
Fix failing to manually trigger a Dag with CronPartitionedTimetable (#62441)
Fix race condition in AssetModel when updating asset partition DagRun — adds mutex lock (#59183)
Fix FAB auth_manager load_user causing PendingRollbackError (#61943)
Fix N+1 query: add joinedload for asset in dags_needing_dagruns() (#60957)
Fix Dag Processor health check threshold matching SchedulerJob/TriggererJob pattern (#58704)
Fix NotMapped exception when clearing task instances with downstream/upstream (#58922)
Fix missing asset events for partitioned DagRun (#61433)
Fix missing partition_key filter in PALK when creating DagRun (#61831)
Fix Dag params API contract broken by earlier change (#56831)
Fix OAuth session race condition causing false 401 errors during login (#61287)
Fix ObjectStoragePath to exclude conn_id from storage options passed to fsspec (#62701)
Fix unable to import list value for Variable (#61508)
Fix plugin registration returning early on duplicate names (#60498)
Fix circular import when using XComObjectStorageBackend (#55805)
Fix deadline alert hashing bug (#61702)
Fix task SDK to read default_email_on_failure/default_email_on_retry from config (#59912)
Fix Celery worker crash on macOS due to non-serializable local function (#62655)
Fix Redis import race condition in Celery executor (#61362)
Fix incorrect state query parameter for task instances in Dashboard (#59086)
Fix TaskInstance.get_dagrun returning None in task_instance_mutation_hook (#60726)
Fix Simple Auth Manager login showing cryptic error on failed authentication (#64303)
Fix dag_display_name property bypass for DagStats query (#64256)
Fix TaskAlreadyRunningError not raised when starting an already-running task instance (#60855)
Fix Teardown tasks not waiting for all in-scope tasks to complete (#64181)
Fix enable_swagger_ui config not respected in API server (#64376)
Fix: add check for xcom permission when result is specified for DagRun wait endpoint (#64415)
Fix conf.has_option not respects default provider metadata (#64209)
Fix teardown scope causing unnecessary database writes during task scheduling (#64558)
Fix live task log output not visible in stdout when using Elasticsearch log forwarding (#64067)
Fix TaskInstance crash when refreshing task weight for non-serialized operators (#64557)
Fix Variables secrets backend conflict check exiting early when multiple backends are configured (#64062)
UI: Fix Dag run accessor key on clear task instance page (#64072)
UI: Fix searchable dropdown not working for Dag params enum fields (#63895)
UI: Fix newline rendering in Dag warning alert (#63588)
UI: Fix XCom edit modal value not repopulating on reopen (#62798)
UI: Fix task duration tooltip not displaying correctly (#63639)
UI: Fix elapsed time not showing for running tasks (#63619)
UI: Fix RenderedJsonField collapse behavior (#63831)
UI: Fix RenderedJsonField not displaying in table cells (#63245)
UI: Fix full-screen log dropdown z-index after Chakra upgrade (#63816)
UI: Fix asset materialization run type display (#63819)
UI: Fix pools with unlimited (-1) slots not rendering correctly (#62831)
UI: Fix DurationChart labels and disable animation flicker during auto-refresh (#62835)
UI: Fix 403 error not shown when unauthorized user re-parses Dag (#61560)
UI: Fix logical date filter on /dagruns page not working (#62848)
UI: Fix inflated total_received count in partitioned Dag runs view (#62786)
UI: Fix edge executor navigation when behind reverse proxy with subpath (#63777)
UI: Fix queries not invalidated on Dag run add/delete (#64269)
UI: Fix RenderedJsonField flickering when collapsed (#64261)
UI: Fix Docs menu REST API link visibility when API docs are disabled (#64359)
UI: Fix TISummaries not refreshing when gridRuns are invalidated (#64113)
UI: Fix guard against null/undefined dates in Gantt chart to prevent RangeError (#64031)
UI: Block polling requests to endpoints that returned 403 Forbidden (#64333)
UI: Fix Gantt view still visible when time range is outside DagRun window (#64179)
UI: Fix Human-in-the-Loop (HITL) operator options not displaying when exactly 4 choices are configured (#64453)
## Miscellaneous
Deprecate api.page_size config in favor of api.fallback_page_limit (#61067)
Improve Dag callback relevancy by passing a context-relevant task instance based on the Dag's final state instead of an arbitrary lexicographical selection (#61274)
Optimize get_dag_runs API endpoint performance (#63940)
Improve historical metrics endpoint performance (#63526)
Add TTL cache with single-flight deduplication to Keycloak filter_authorized_dag_ids (#63184)
Reduce Celery worker memory usage with gc.freeze (#62212)
Eliminate duplicate JOINs in get_task_instances endpoint (#62910)
Replace large IN clause in asset queries with CTE and JOIN for better SQL performance (#62114)
Add row lock to prevent race conditions during asset-triggered DagRun creation (#60773)
Add ConnectionResponse serializer safeguard to prevent accidental sensitive field exposure (#63883)
Add missing dag_id filter on DagRun task instances API query (#62750)
Add missing HTTP timeout to FAB JWKS fetching (#63058)
Add additional permission check in asset materialization endpoint (#63338)
Filter backfills list by readable Dags (authorization enforcement) (#63003)
Hide SQL statements in exception details when expose_stacktrace is disabled (#63028)
Use default max depth to redact Variable values in API responses (#63480)
Validate update_mask fields in PATCH API endpoints against Pydantic models (#62657)
Align key/id path validation for variables and connections in Execution API (#63897)
Add order_by parameter to GET /permissions endpoint for pagination consistency (#63418)
Implement truncation logic for rendered template values (#61878)
Add BaseXcom to airflow.sdk public exports (#63116)
Make TaskSDK conf respect default config from provider metadata (#62696)
Add OTel trace import shim via airflow.sdk.observability.trace (#63554)
Improve 3.2.0 deadline migration performance (#63920)
Improve 3.2.0 downgrade migration for external_executor_id on PostgreSQL (#63625)
Skip backfilling old DagRun.created_at during migration for faster upgrades (#63825)
Add INFO-level logging to asset scheduling path (#63958)
Improve log file template for ExecuteCallback by including dag_id and run_id (#62616)
Improve Dag processor timeout logging clarity (#62328)
Deprecate get_connection_form_widgets and get_ui_field_behaviour hook methods (#63711)
Add missing deprecation warnings for [workers] config section (#63659)
Expose TaskInstance API for external task management (#61568)
Remove deprecated airflow.datasets, airflow.timetables.datasets, and airflow.utils.dag_parsing_context modules (#62927)
Remove PyOpenSSL from core dependencies (#63869)
Optimize fail-fast check to avoid loading SerializedDAG (#56694)
Improve performance of task queue processing by switching from pop(0) to popleft() (#61376)
Optimize K8s API usage for watching pod events, fixing hanging communication (#59080)
Remove N+1 database queries for team names (#61471)
Improve XCom value handling in extra links API (#61641)
Remove .git folder from versions in GitDagBundle to reduce storage size (#57069)
Deprecate subprocess exec utils from airflow.utils.process_utils (#57193)
Improve error handling in edge worker on 405 responses (#60425)
Improve deferrable KubernetesPodOperator handling of deleted pods between polls (#56976)
Improve event log entries when a pod fails for K8s executor (#60800)
Refactor XCom API to use shared serialization constants (#64148)
Improve temporal mapper to be timezone aware for asset partitioning (#62709)
Improve dag version inflation checker logic and fix false-positive detection (#61345)
Rename ToXXXMapper to StartOfXXXMapper in partition-mapper for clarity (#64160)
Run DB check only for core components in prod entrypoint (#63413)
Fix partitioned asset events incorrectly triggering non-partition-aware Dags (#63848)
Improve partitioned DagRun sorting by partition_date (#62866)
Allow gray, black, and white color tokens in AIRFLOW__API__THEME config (#64232)
Add parent task spans and nest worker/trigger spans for improved observability (#63839)
UI: Enhance code view to support search and diff (#55467)
UI: Improve UX for adding custom DeadlineReferences (#57222)
UI: Enhance FilterBar with DateRangeFilter for compact UI (#56173)
UI: Move deadline alerts into their own table for UI integration (#58248)
UI: Persist tag filter selection in Dag grid view (#63273)
UI: Show HITL review tab only for review-enabled task instances (#63477)
UI: Updated button styles for adding Connections, Variables, and Pools (#62607)
UI: Add clear permission toast for 403 errors on user actions (#61588)
## Doc Only Changes
Add documentation marking pre/post-execute task hooks as GA (no longer experimental) (#59656)
Add RedisTaskHandler configuration example (#63898)
Add documentation explaining difference between deferred vs async operators (#63500)
Add auth manager section in multi-team documentation (#63208)
Add documentation about shared libraries in _shared folders (#63468)
Clarify plugin folder module registration in modules_management docs (#63634)
Clarify max_active_tasks Dag parameter documentation (#63217)
Clarify HLL in extraction precedence docs (#63723)
Clarify Ubuntu/Debian venv requirement in quick start guide (#63244)
Fix Git connection docs to match actual GitHook parameters (#63265)
Mention Python 3.14 support in docs (#63950)
Add Dag documentation for example_bash_decorator (#62948)
Add Russian translation for UI (#63450)
Add Hungarian translation (#62925)
Complete Traditional Chinese translations (#62652)
Add asset partition documentation (#63262)
Add guide for dag version inflation and its checker (#64100)
Release Date: 2022-10-01
Add logging options to docker operator (#26653)
Add pre-commit hook for custom_operator_name (#25786)
Implement ExternalPythonOperator (#25780)
Add logging options to docker operator (#26653)
Add pre-commit hook for custom_operator_name (#25786)
Implement ExternalPythonOperator (#25780)
Nothing published for this version
Remove deprecated Airflow 2.x modules and legacy imports
We are thrilled to announce the release of Apache Airflow 3.1.0, an update that puts humans at the center of data workflows.
Read more about what 3.1.0 brings in https://airflow.apache.org/blog/airflow-3.1.0/
📦 PyPI: https://pypi.org/project/apache-airflow/3.1.0/
📚 Core Airflow Docs: https://airflow.apache.org/docs/apache-airflow/3.1.0/
📚 Task SDK Docs: https://airflow.apache.org/docs/task-sdk/1.1.0/
🛠️ Release Notes: https://airflow.apache.org/docs/apache-airflow/3.1.0/release_notes.html
🚏 Constraints: https://github.com/apache/airflow/tree/constraints-3.1.0
Apache Airflow 3.1.0 represents an extraordinary community effort, showcasing the vibrant ecosystem that drives this project forward with 163 contributors making this release possible across 1,400+ commits.
<img width="1600" height="775" alt="favorite" src="https://github.com/user-attachments/assets/0dec07d2-56b6-4b02-adcc-6431d89fa52c" /> <img width="1871" height="1118" alt="gantt" src="https://github.com/user-attachments/assets/3a53106f-352c-477c-9398-f2f7c5ae8b16" />
SQLAlchemy 2.0 support with various compatibility fixes for Python 3.13 (#52233, #52518, #54940)psycopg3 postgres driver (#52976)XCom browsing with filtering and improved navigation (#54049)HITLOperator, ApprovalOperator, HITLEntryOperator) for human decision workflows (#52868)has_import_errors filter to Core API GET /dags endpoint (#54563)/plugins API with warnings for invalid plugins (#55673)dag_display_name aliases for improved API consistency (#50332, #50065, #50014, #49933, #49641)XCom validation to prevent empty keys in XCom.set() and XCom.get() operations (#46929)iframe_views to backend plugin support (#51003)QUEUED runs with null start_date (#52668)ti_successes and related metrics in Airflow 3.0 Task SDK (#55322)clearTaskInstances API: Restore include_past/future support on UI (#54416)XCom access in DAG processor callbacks for notifiers (#55542)default_timezone is not UTC (#54431)lineno of logger calls are present in Task Logs (#55581)serialized_dag table (#54972)LocalExecutor race condition where tasks could start before database state was committed (#56010)dag_stale_not_seen_duration (#55601, #55684)dag_id column in DAG Runs and Task Instances pages for better navigation (#55648)--preview flag from ruff check instructions for Airflow 3 upgrade path (#55516)Airflow 3.1 introduces Human-in-the-Loop (HITL) functionality that enables workflows to pause and wait for human decision-making. This powerful feature is particularly valuable for AI/ML workflows, content moderation, and approval processes where human judgment is essential.
HITL tasks pause execution in a deferred state while waiting for human input via the Airflow UI. Users with appropriate roles can see pending tasks, review context (including XCom data and DAG parameters), and complete actions through intuitive web forms. The feature also supports API-driven interactions for custom UIs and notification integration.
For detailed usage instructions, see /tutorial/hitl.
Note: HITL operators require apache-airflow-providers-standard package and Airflow 3.1+.
Airflow 3.1 advances the decoupling of the Task SDK from Airflow Core through improved DAG serialization with versioned contracts. While complete code separation is planned for Airflow 3.2.0, the serialization foundation enables independent upgrades when components are deployed separately.
For DAG Authors: Import constructs from airflow.sdk namespace:
from airflow.sdk import DAG, task, asset
Access to latest authoring features with forward compatibility
Reduced dependency on server-side Airflow versions
For Platform Teams: Foundation for independent upgrades:
Schema compliance ensures compatibility across versions
Deployment flexibility when components are separated
Reduced coordination overhead between development and operations teams
For technical details on the serialization contract, see /administration-and-deployment/dag-serialization.
Deadline Alerts provide proactive monitoring for DAG execution by automatically triggering notifications when time thresholds are exceeded. This helps ensure SLA compliance and timely completion of critical workflows.
Configure deadline monitoring by specifying:
Reference point: Choose from DAG run queued time, logical date, or fixed datetime
Interval: Time threshold relative to the reference point (positive or negative)
Callback: Response action using Airflow Notifiers or custom functions
Example use cases:
Alert if a daily ETL hasn't completed 1 hour after its scheduled time
Notify stakeholders 30 minutes before a critical deadline
Escalate when resource-constrained DAGs remain queued too long
Current Limitations: Deadline Alerts currently support only asynchronous callbacks (AsyncCallback). Support for synchronous callbacks (SyncCallback) is planned for a future release.
For configuration details and examples, see /howto/deadline-alerts.
Warning
Deadline Alerts are experimental in 3.1 and may change in future versions based on user feedback.
Airflow 3.1 delivers comprehensive internationalization (i18n) support, making the web interface accessible to users worldwide. The React-based UI now supports 17 languages with robust translation infrastructure.
Supported Languages:
Arabic
Catalan
Dutch
English
French
German
Hebrew
Hindi
Hungarian
Italian
Korean
Polish
Portuguese
Simplified Chinese
Spanish
Traditional Chinese
Turkish
The translation system includes automated completeness checking and clear contribution guidelines for community translators.
Airflow 3.1 introduces a modern plugin architecture enabling rich integrations through React components and external views. This extensibility framework allows organizations to embed custom dashboards, monitoring tools, and domain-specific interfaces directly within the Airflow UI.
New Plugin Capabilities:
React Apps: Full-featured React applications integrated into Airflow navigation
External Views: Embed external web applications via iframe with seamless authentication
Dashboard Integration: Custom widgets and panels for operational dashboards
Menu Integration: Add custom navigation items and organize tools logically
Developer Experience:
Hot reloading during development with airflow-react-plugin dev tools
TypeScript support and modern React patterns
Standardized plugin loading and validation
Comprehensive documentation and boilerplate generation
This plugin system replaces legacy Flask-based approaches with modern web standards, improving performance, maintainability, and user experience.
For more details and examples, see /howto/custom-view-plugin.
Airflow 3.1 brings significant UI improvements including rebuilt Calendar and Gantt chart views for the modern React UI, comprehensive filtering capabilities, and a refreshed visual design system.
Visual Design Improvements
The UI now features an updated color palette leveraging Chakra UI semantic tokens, providing better consistency, accessibility, and theme support across the interface. This modernization improves readability and creates a more cohesive visual experience throughout Airflow.
Rebuilt Views and Enhanced Filtering
The Calendar and Gantt views from Airflow 2.x have been rebuilt for the modern React UI, along with enhanced filtering capabilities across all views. These improvements provide better performance and a more consistent user experience with the rest of the modern Airflow interface.
DAG Dashboard Organization
Users can now pin and favorite DAGs for better dashboard organization, making it easier to find and prioritize frequently used workflows. This feature is particularly valuable for teams managing large numbers of DAGs, providing quick access to critical workflows without searching through extensive DAG lists.
Airflow 3.1 introduces a new streaming API endpoint that allows applications to watch DAG runs until completion, enabling more responsive integration patterns for real-time and inference workflows.
New Streaming Endpoint: The /dags/{dag_id}/dagRuns/{dag_run_id}/wait endpoint repeatedly emits JSON updates at specified intervals until the DAG run reaches a finished state.
# Watch a DAG run with 2-second polling interval, including XCom results
curl -X GET "http://localhost:8080/api/v2/dags/ml_pipeline/dagRuns/manual_2024_01_15/wait?result=inference_task" \
-H "Accept: application/x-ndjson"
This enables use cases like:
ML Inference Monitoring: Trigger inference DAGs and wait for completion before returning results
Real-time Processing: Monitor event-driven workflows with immediate response requirements
API Integration: Build responsive services that react to DAG completion without polling
Synchronous Workflows: Create quasi-synchronous behavior for workflows that need immediate feedback
ALL_DONE_MIN_ONE_SUCCESS: This rule triggers when all upstream tasks are done (success, failed) and at least one has succeeded, filling a gap between existing trigger rules for complex workflow patterns. Skipped upstream tasks work as usually - they skip downstream task.
DAG parsing duration is now exposed in the UI, providing better visibility into DAG processing performance and helping identify parsing bottlenecks. This information is displayed alongside other DAG metadata to assist with performance optimization.
Support for Python 3.9 has been removed, as it has reached end-of-life. Airflow 3.1.0 requires Python 3.10, 3.11, 3.12 or 3.13.
Webserver Configuration Reorganization
Several webserver configuration options have been moved to the api section for better organization:
[webserver] log_fetch_timeout_sec → [api] log_fetch_timeout_sec
[webserver] hide_paused_dags_by_default → [api] hide_paused_dags_by_default
[webserver] page_size → [api] page_size
[webserver] default_wrap → [api] default_wrap
[webserver] require_confirmation_dag_change → [api] require_confirmation_dag_change
[webserver] auto_refresh_interval → [api] auto_refresh_interval
Unused configuration options have been removed:
[webserver] instance_name_has_markup
[webserver] warn_deployment_exposure
API Server Logging Configuration
The API server configuration option [api] access_logfile has been replaced with [api] log_config to align with uvicorn's logging configuration. The new option accepts a path to a logging configuration file compatible with logging.config.fileConfig, providing more flexible logging configuration.
Security Improvement: XCom Deserialization
The enable_xcom_deserialize_support configuration option has been removed as a security improvement. This option previously allowed deserializing unknown objects in the API, which posed a security risk due to potential remote code execution vulnerabilities when deserializing arbitrary Python objects.
The XCom display improvements now handle showing non-native XComs (like custom objects, Assets, datetime objects) in a human-readable way through safer methods that don't require deserializing unknown objects in the API server. This provides better user experience when viewing XCom data in the Airflow UI while eliminating the security risk.
Asset API Key Rename
The consuming_dags key in asset API responses has been renamed to scheduled_dags to better reflect its purpose. This key contains only DAGs that use the asset in their schedule argument, not all DAGs that technically use the asset.
Removed Functions
The following functions have been removed from the task-sdk (airflow.sdk.definitions.taskgroup) and moved to server-side API services:
get_task_group_children_getter
task_group_to_dict
These functions are now internal to Airflow's API layer and should not be imported directly by users.
The default number of API server workers ([api] workers) has been reduced from 4 to 1.
With FastAPI, sync code runs in external thread pools, making multiple workers within a single process less necessary. Additionally, with uvicorn's spawn behavior instead of fork, there is no shared copy-on-write memory between workers, so horizontal scaling with multiple API server instances is now the recommended approach for better resource utilization and fault isolation.
A good starting point for the number of workers is to set it to the number of CPU cores available. If you do have multiple CPU cores available for the API server, consider deploying multiple API server instances instead of increasing the number of workers.
Most users should not notice the difference, but it is now possible to emit structured log key/value pairs from tasks.
If your class subclasses LoggingMixin (which all BaseHook and BaseOperator do -- i.e. all hooks and operators) then self.log is now a structloglogger.
The advantage of using structured logging is that it is much easier to find specific information about log message, especially when using a central store such as OpenSearch/Elastic/Splunk etc. You don't have to make any changes, but you can now take advantage of this.
# Inside a Task/Hook etc.
# Before:
# self.log.info("Registering adapter %r", item.name)
# Now:
self.log.info("Registering adapter", name=item.name)
This will produce a log that (in the UI) will look something like this:
[2025-09-16 10:36:13] INFO - Registering adapter name="adapter1"
or in JSON (i.e. the log files on disk):
{"timestamp": "2025-09-16T10:36:13Z", "log_level": "info", "event": "Registering adapter", "name": "adapter1"}
You can also use structlog loggers at the top level of modules etc, and stdlib both continue to work:
import logging
import structlog
log1 = logging.getLogger(__name__)
log2 = strcutlog.get_logger(__name__)
log1.info("Loading something from %s", __name__)
log2.info("Loading something", source=__name__)
(You can't add arbitrary key/value pairs to stdlib, but the normal percent-formatter approaches still work fine.)
The deserializer interface in airflow.serialization.serializers has changed for improved security.
Before 3.1.0:
def deserialize(classname: str, version: int, data: Any)
Starting with 3.1.0:
def deserialize(cls: type, version: int, data: Any)
The class loading is now handled in serde.py, and the deserializer receives the loaded class directly rather than a classname string. This update avoids the use of import_string in the deserializer, making deserialization more secure.
Add Calendar and Gantt chart views to modern React UI with enhanced filtering (#54252, #51667)
Add Python 3.13 support for Airflow runtime and dependencies (#46891)
Add SQLAlchemy 2.0 support with various compatibility fixes for Python 3.13 (#52233, #52518, #54940)
Add support for the psycopg3 postgres driver (#52976)
Add ability to track & display user who triggers DAG runs (#51738, #53510, #54164, #55112)
Add toggle for log grouping in task log viewer for better organization (#51146)
Add tag filtering improvements with Any/All selection options (#51162)
Add comprehensive filtering for DAG runs, task instances, and audit logs (#53652, #54210, #55082)
Add XCom browsing with filtering and improved navigation (#54049)
Add bulk task instance actions and deletion endpoints (#50443, #50165, #50235)
Add DAG run deletion functionality through UI (#50368)
Add test connection button for connection validation (#51055)
Add hyperlink support for URLs in XCom values (#54288)
Add pool column to task instances list and improve pool integration (#51185, #51031)
Add drag-and-drop log grouping and improved log visualization (#51146)
Add color support for XCom JSON display (#51323)
Add configuration column to DAG runs page (#51270)
Add enhanced note visibility and management in task headers (#51764, #54163)
Introduce React plugin system (AIP-68) for modern UI extensions (#52255)
Add support for external view plugins via iframe integration (#51003, #51889)
Add dashboard integration capabilities for custom React apps (#54131, #54144)
Add comprehensive plugin development tools and documentation (#53643)
Implement complete HITL operator suite (HITLOperator, ApprovalOperator, HITLEntryOperator) for human decision workflows (#52868)
Add HITL UI integration with role-based access and form handling (#53035)
Add HITL API endpoints with filtering and query support (#53376, #53923)
Add HITL utility functions for generating URLs to required actions page (#54827)
Improve HITL user experience with bug fixes, UI enhancements, and data model consistency (#55463, #55539, #55575, #55546, #55543, #55536, #55535)
Add ordering and filtering support for HITL details endpoints (#55217)
Add "No Response Received" required action state (#55149)
Add operator filter for HITL task instances (#54773)
Implement deadline alert system for proactive DAG monitoring (AIP-86) (#53951, #53903, #53201, #55086)
Add configurable reference points and notification callbacks (#50677, #50093)
Add deadline calculation and tracking in DAG execution lifecycle (#51638, #50925)
Add comprehensive UI translation support for 16 languages (#51266, #51038, #51219, #50929, #50981, #51793 and more)
Add right-to-left (RTL) layout support for Arabic and Hebrew (#51376)
Add language selection interface and browser preference detection (#51369)
Add translation completeness validation and automated checks (#51166, #51131)
Add calendar data API endpoints for DAG execution visualization (#52748)
Add endpoint to watch DAG runs until completion (#51920, #53346)
Add DAG run ID pattern search functionality (#52437)
Add multi-sorting capabilities for improved data navigation (#53408)
Add bulk connection deletion API and UI (#51201)
Add task group detail pages across DAG runs (#50412, #50309)
Add asset event tracking with last event timestamps (#50060, #50279)
Add has_import_errors filter to Core API GET /dags endpoint (#54563)
Add dag_version filter to get_dag_runs endpoint (#54882)
Add pattern search for event log endpoint (#55114)
Add dry_run support with consistent audit log handling (#55116)
Add utility functions for generic filter counting (#54817)
Add keyboard navigation for Grid view interface (#51784)
Add improved error handling for plugin import failures (#49643)
Add plugin validation in /plugins API with warnings for invalid plugins (#55673)
Improve accessibility for screen readers and assistive technologies with proper language detection (#55839)
Add enhanced variable management with upsert operations (#48547)
Add favorites/pinning support for DAG dashboard organization (#51264)
Add system theme support with automatic OS preference detection (#52649)
Add hotkey shortcut to toggle between Grid and Graph views (#54667)
Add queued DAGs filter button to DAGs page (#55052)
Add DAG parsing duration visibility in UI (#54752)
Add owner links support in DAG Header UI for better navigation (#50627)
Add dag_display_name aliases for improved API consistency (#50332, #50065, #50014, #49933, #49641)
Add enhanced search capabilities with SearchParamsKeys constants (#55218)
Add ALL_DONE_MIN_ONE_SUCCESS trigger rule for flexible task dependencies (#53959)
Add fail_when_dag_is_paused parameter to TriggerDagRunOperator for better control (#48214)
Add XCom validation to prevent empty keys in XCom.set() and XCom.get() operations (#46929)
Add collapsible plugin menu when multiple plugins are present (#55265)
Add external view plugin categories (admin, browse, docs, user) (#52737)
Add iframe plugins integration to DAG pages (#52795)
Add plugin error display in UI with comprehensive error handling (#49643, #49436)
Add collapsible failed task logs to prevent React error overflow (#54377)
Add dynamic legend system for calendar view (#55155)
Add React UI for Edge functionality (#53563)
Add pending actions display to DAG UI (#55041)
Add description field for filter parameters (#54903)
Add Catalan language support to Airflow UI (#55013)
Add Hungarian language support to Airflow UI (#54716)
Add map_index validation in categorize_task_instances (#54791)
Add Grid view UX improvements (#54846)
Add HITL UX improvements for better user experience (#54990)
Add async support for Notifiers (AIP-86) (#53831)
Add filtering capabilities for tasks view (#54484)
Add asset-based filtering support to DAG API endpoint (#54263)
Add iframe plugins to navigation (#51706)
Add RTL (right-to-left) layout support for Arabic and Hebrew (#51376)
Add test connection button to UI (#51055)
Add task instance bulk actions endpoint (#50443)
Add connection bulk deletion functionality (#51201)
Add pool column to task instances list (#51185)
Add iframe_views to backend plugin support (#51003)
Add keyboard shortcuts to clear and mark state for task instances and DAG runs (#50885)
Add deadline relationship to DAG runs and deadline model (#50925, #50093)
Add DAG run deletion UI (#50368)
Add task instance deletion UI and endpoint (#50235, #50165)
Switch all airflow logging to structlog (#52651, #55434, #55431, #55638)
Add Filter Bar to Audit Log (#55487)
Add Filters UI for Asset View (#54640)
Update color palette and leverage Chakra semantic tokens (#53981, #55739)
Improve calendar view UI with enhanced tooltips and visual fixes (#55476)
Fix DAG list filtering to include QUEUED runs with null start_date (#52668)
Fix XCom deletion failure for mapped task instances through bulk deletion API (#51850)
Fix XCom deletion failure for mapped task instances (#54954)
Fix task timeout handling within task SDK (#54089)
Fix task instance tries API duplicate entries (#50597)
Fix connection validation and type checking during construction (#54759)
Fix mapped task instance index display in Task Instances tab (#55363)
Fix Gantt chart state mismatch with Grid view (#55300)
Fix Gantt chart status color display issues (#55296)
Fix XCom mapping for dynamically-mapped task groups (#51556)
Fix missing ti_successes and related metrics in Airflow 3.0 Task SDK (#55322)
Fix bulk operation permissions for connection, pool and variable (#55278)
Fix clearTaskInstances API: Restore include_past/future support on UI (#54416)
Fix migration when XCom has NaN values (#53812)
Fix HITL related UI schema generated by prek hooks (#55204)
Fix consistent no-log handling for tasks with try_number=0 in API and UI (#55035)
Fix timezone conversion in datetime trigger parameters (#54593)
Fix audit log payload for DAG pause/unpause actions (#55091)
Fix pushing None as an XCom value (#55080)
Fix scheduler processing of cleared running tasks stuck in RESTARTING state (#55084)
Fix XCom deletion failure for mapped task instances (#54954)
Fix outgoing graph edges should exit opposite of incoming edges (#54789)
Fix external links in Navigation buttons (#52220)
Fix Error when viewing DAG details of a no longer configured bundle (#52086)
Fix compatibility with new numpy and pandas versions (#52071)
Fix connection recovery from URI when host has protocol (#51953)
Fix last DAG run not showing on DAG listing (#51115)
Fix task instance tries API returning duplicate entries (#50597)
Fix Graph view vanishing and loading issues (#53886, #54756)
Fix rendered template display formatting for better readability (#53657)
Fix Grid view expand/collapse button functionality (#54257)
Fix tooltip visibility and positioning issues (#53913)
Fix grid keyboard navigation focus management (#54271)
Fix plugin registration for invalid objects and middleware registration (#55264, #55399)
Fix external links for plugins with undefined URL routes (#55221)
Fix language display consistency and flag representation (#51560, #51177)
Fix RTL layout rendering for Arabic and Hebrew interfaces (#51853)
Fix graph export cropping when view is partial (#55012)
Fix log viewer "Toggle Source" to hide only source fields, not all structured log fields (#55474)
Output on stdout/stderr from within tasks is now filterable in the Sources list in the UI log view (#55508)
Redact JWT tokens in task logs (#55499)
Fix grid view to handle long task name (#55332)
Allow slash characters in Variable keys similar to Airflow 2.x (#55324)
Fix Grid cache invalidation for multi-run task operations (#55504)
Fix Gantt chart rendering issues (#55554)
Fix XCom access in DAG processor callbacks for notifiers (#55542)
Fix alignment of arrows in RTL mode for right-to-left languages (#55619)
Fix connection form extras not inferring correct type in UI (#55492)
Fix incorrect log timestamps in UI when default_timezone is not UTC (#54431)
Fix handling of priority_weight for DAG processor callbacks (#55436)
Fix pointless requests from Gantt view when there is no Run ID (#55668)
Ensure filename and lineno of logger calls are present in Task Logs (#55581)
Fix DAG disappearing after callback execution in stale detection (#55698)
Fix DB downgrade to Airflow 2 when fab tables exists (#55738)
Fix UI stats endpoint causing dashboard loading issues (#55733)
Fix unintended console output when DAG not found in serialized_dag table (#54972)
Fix scheduler handling of orphaned tasks from Airflow 2 during upgrade (#55848)
Fix logging format to respect existing configuration during upgrade to prevent unexpected log format changes (#55824)
Fix Grid view crashes when DAG version information is missing (#55771)
Fix compatibility for custom triggers migrating from Airflow 2.x that use synchronous connection calls (#55799)
Fix DAG runs triggered from UI incorrectly marked as REST API triggers instead of UI triggers (#54650)
Fix XCom API responses failing when encountering non-serializable objects by falling back to string representation (#55880)
Fix asset queue display in UI showing incorrect timestamps for deleted queue events (#54652)
Fix SQLite database migrations failing due to foreign key constraint handling (#55883)
Fix DAG deserialization failure when using non-default weight_rule values like 'absolute' (#55906)
Fix async connection retrieval in triggerer context preventing event loop blocking (#55812)
Fix Airflow downgrade compatibility by handling serialized DAG format conversion from v3 to v2 (#55975)
Fix 'All Log Levels' filter not working in task log viewer (#55851)
Fix Grid view scrollbar overlapping issues on Firefox browser (#55960)
Fix Gantt chart misalignment with Grid view layout (#55995)
Fix Grid view task names being extremely collapsed and unreadable when displaying many DAG runs (#55997)
Fix LocalExecutor race condition where tasks could start before database state was committed (#56010)
Move secrets masker to shared distribution for better modularity (#54449)
Move email notifications from scheduler to DAG processor for better architecture (#55238)
Add graph UI load optimization with latest run info endpoint (#53429)
Optimize UI bundle size by moving translations to dynamic loading (#51735)
Relocate Task SDK components for improved separation (#55174, #54795)
Refactor trigger rule utilities and weight rule consolidation (#54797, #53393)
Remove deprecated Airflow 2.x modules and legacy imports (#50482)
Clean up unused code and improve module organization (#52176, #52173, #53031)
Add SQLAlchemy 2.0 CI support for future compatibility (#52233)
Improve test fixtures and SDK communication testing (#54795, #50603)
Add translation completeness linting and validation tools (#51166)
Upgrade to latest versions of important dependencies (#55350)
Move webserver configuration options to API section (#50693, #50656)
Improve DAG bundle handling and versioning support (#47592)
Add database management CLI tools for external database operations (#50657)
Add comprehensive HITL operator documentation and examples (#54618)
Add guards for registering middlewares from plugins (#55399)
Optimize Gantt group expansion with de-bouncing and deferred rendering (#55334)
Differentiate between triggers and watchers currently running for better visibility (#55376)
Removed unused config: dag_stale_not_seen_duration (#55601, #55684)
Update UI's query client strategy for improved performance (#55528)
Unify datetime format across the UI for consistency (#55572)
Mark React Apps as Experimental for Airflow 3.1 release (#55478)
Improve OOM error messaging for clearer task failure diagnosis (#55602)
Display responder username for better audit trail in HITL workflows (#55509)
The constraint file do not contain developer dependencies anymore (#53631)
Add hyperlinks to dag_id column in DAG Runs and Task Instances pages for better navigation (#55648)
Add responsive web design (RWD) support to Grid view (#55745)
Add comprehensive Human-in-the-Loop operator tutorial and examples (#54618)
Add deadline alerts configuration and usage documentation (#53727)
Make term Dag consistent in docs task-sdk (#55100)
Add migration guide for upgrading from legacy SLA functionality to deadline alerts (#55743)
Add DAG bundles triggerer limitation documentation (#55232)
Add deadline alerts usage guides and best practices (#53727)
Remove --preview flag from ruff check instructions for Airflow 3 upgrade path (#55516)
Add documentation for context parameter (#55377)
Release Date: 2022-07-16
Force-remove container after DockerOperator execution (#23160)
'DockerOperator' fix cli.logs giving character array instead of string (#24726)
Force-remove container after DockerOperator execution (#23160)
'DockerOperator' fix cli.logs giving character array instead of string (#24726)
Nothing published for this version
📣 We are proud to announce the General Availability of Apache Airflow® 3.0, the most significant release in the project’s history.
📣 We are proud to announce the General Availability of Apache Airflow® 3.0, the most significant release in the project’s history.
Airflow 3.0 builds on the foundation of Airflow 2 and introduces a new service-oriented architecture, a modern React-based UI, enhanced security, and a host of long-requested features such as DAG versioning, improved backfills, event-driven scheduling, and support for remote execution.
You can read more about what 3.0 brings in https://airflow.apache.org/blog/airflow-three-point-oh-is-here/.
📦 PyPI: https://pypi.org/project/apache-airflow/3.0.0/ 📚 Docs: https://airflow.apache.org/docs/apache-airflow/3.0.0 🛠️ Release Notes: https://airflow.apache.org/docs/apache-airflow/3.0.0/release_notes.html 🪶 Sources: https://airflow.apache.org/docs/apache-airflow/3.0.0/installation/installing-from-sources.html
This is the result of 300+ developers within the Airflow community working together tirelessly for many months! A huge thank you to all of them for their contributions.
Resources
We are proud to announce the General Availability of Apache Airflow 3.0 — the most significant release in the project's history. This version introduces a service-oriented architecture, a stable DAG authoring interface, expanded support for event-driven and ML workflows, and a fully modernized UI built on React. Airflow 3.0 reflects years of community investment and lays the foundation for the next era of scalable, modular orchestration.
Service-Oriented Architecture: A new Task Execution API and airflow api-server enable task execution in remote environments with improved isolation and flexibility (AIP-72).
Edge Executor: A new executor that supports distributed, event-driven, and edge-compute workflows (AIP-69), now generally available.
Stable Authoring Interface: DAG authors should now use the new airflow.sdk namespace to import core DAG constructs like @dag, @task, and DAG.
Scheduler-Managed Backfills: Backfills are now scheduled and tracked like regular DAG runs, with native UI and API support (AIP-78).
DAG Versioning: Airflow now tracks structural changes to DAGs over time, enabling inspection of historical DAG definitions via the UI and API (AIP-66).
Asset-Based Scheduling: The dataset model has been renamed and redesigned as assets, with a new @asset decorator and cleaner event-driven DAG definition (AIP-74, AIP-75).
Support for ML and AI Workflows: DAGs can now run with logical_date=None, enabling use cases such as model inference, hyperparameter tuning, and non-interval workflows (AIP-83).
Removal of Legacy Features: SLAs, SubDAGs, DAG and Xcom pickling, and several internal context variables have been removed. Use the upgrade tools to detect deprecated usage.
Split CLI and API Changes: The CLI has been split into airflow and airflowctl (AIP-81), and REST API now defaults to logical_date=None when triggering a new DAG run.
Modern React UI: A complete UI overhaul built on React and FastAPI includes version-aware views, backfill management, and improved DAG and task introspection (AIP-38, AIP-84).
Migration Tooling: Use ruff and airflow config update to validate DAGs and configurations. Upgrade requires Airflow 2.7 or later and Python 3.9–3.12.
Airflow 3.0 introduces the most significant set of changes since the 2.0 release, including architectural shifts, new execution models, and improvements to DAG authoring and scheduling.
Airflow now supports a service-oriented architecture, enabling tasks to be executed remotely via a new Task Execution API. This API decouples task execution from the scheduler and introduces a stable contract for running tasks outside of Airflow's traditional runtime environment.
To support this, Airflow introduces the Task SDK — a lightweight runtime environment for running Airflow tasks in external systems such as containers, edge environments, or other runtimes. This lays the groundwork for language-agnostic task execution and brings improved isolation, portability, and extensibility to Airflow-based workflows.
Airflow 3.0 also introduces a new airflow.sdk namespace that exposes the core authoring interfaces for defining DAGs and tasks. DAG authors should now import objects like DAG, @dag, and @task from airflow.sdk rather than internal modules. This new namespace provides a stable, forward-compatible interface for DAG authoring across future versions of Airflow.
Airflow 3.0 introduces the Edge Executor as a generally available feature, enabling execution of tasks in distributed or remote compute environments. Designed for event-driven and edge-compute use cases, the Edge Executor integrates with the Task Execution API to support task orchestration beyond the traditional Airflow runtime. This advancement facilitates hybrid and cross-environment orchestration patterns, allowing task workers to operate closer to data or application layers.
Backfills are now fully managed by the scheduler, rather than being launched as separate command-line jobs. This change unifies backfill logic with regular DAG execution and ensures that backfill runs follow the same scheduling, versioning, and observability models as other DAG runs.
Airflow 3.0 also introduces native UI and REST API support for initiating and monitoring backfills, making them more accessible and easier to integrate into automated workflows. These improvements lay the foundation for smarter, safer historical reprocessing — now available directly through the Airflow UI and API.
Airflow 3.0 introduces native DAG versioning. DAG structure changes (e.g., renamed tasks, dependency shifts) are now tracked directly in the metadata database. This allows users to inspect historical DAG structures through the UI and API, and lays the foundation for safer backfills, improved observability, and runtime-determined DAG logic.
Note: DAG bundles are not initialized in the triggerer. In practice, this means that triggers cannot come from a DAG bundle. This is because the triggerer does not deal with changes in trigger code over time, as everything happens in the main process. Triggers can come from anywhere else on sys.path instead.
Airflow 3.0 ships with a completely redesigned user interface built on React and FastAPI. This modern architecture improves responsiveness, enables more consistent navigation across views, and unlocks new UI capabilities — including support for DAG versioning, asset-centric DAG definitions, and more intuitive filtering and search.
The new UI replaces the legacy Flask-based frontend and introduces a foundation for future extensibility and community contributions.
The concept of Datasets has been renamed to Assets, unifying terminology with common practices in the modern data ecosystem. The internal model has also been reworked to better support future features like asset partitions and validations.
The @asset decorator and related changes to the DAG parser enable clearer, asset-centric DAG definitions, allowing Airflow to more naturally support event-driven and data-aware scheduling patterns.
This renaming impacts modules, classes, functions, configuration keys, and internal models. Key changes include:
Dataset → Asset
DatasetEvent → AssetEvent
DatasetAlias → AssetAlias
airflow.datasets.* → airflow.sdk.*
airflow.timetables.simple.DatasetTriggeredTimetable → airflow.timetables.simple.AssetTriggeredTimetable
airflow.timetables.datasets.DatasetOrTimeSchedule → airflow.timetables.assets.AssetOrTimeSchedule
airflow.listeners.spec.dataset.on_dataset_created → airflow.listeners.spec.asset.on_asset_created
airflow.listeners.spec.dataset.on_dataset_changed → airflow.listeners.spec.asset.on_asset_changed
core.dataset_manager_class → core.asset_manager_class
core.dataset_manager_kwargs → core.asset_manager_kwargs
Airflow 3.0 removes the legacy schedule_interval and timetable parameters. DAGs must now use the unified schedule field for all time- and event-based scheduling logic. This simplifies DAG definition and improves consistency across scheduling paradigms.
Airflow 3.0 changes the default behavior for new DAGs by setting catchup_by_default = False in the configuration file. This means DAGs that do not explicitly set catchup=... will no longer backfill missed intervals by default. This change reduces confusion for new users and better reflects the growing use of on-demand and event-driven workflows.
The default DAG schedule has been changed to None from @once.
Task code can no longer directly access the metadata database. Interactions with DAG state, task history, or DAG runs must be performed via the Airflow REST API or exposed context. This change improves architectural separation and enables remote execution.
Airflow no longer supports triggering DAG runs with a logical date in the future. This change aligns with the logical execution model and removes ambiguity in backfills and event-driven DAGs. Use logical_date=None to trigger runs with the current timestamp.
For DAG runs triggered by an Asset event or through the REST API without specifying a logical_date, Airflow now sets logical_date=None by default. These DAG runs do not have a data interval, and attempting to access data_interval_start, data_interval_end, or logical_date from the task context will raise a KeyError.
DAG authors should use dag_run.logical_date and perform appropriate checks or fallbacks if supporting multiple trigger types. This change improves consistency with event-driven semantics but may require updates to existing DAGs that assume these values are always present.
Airflow 3.0 refines task callback behavior to improve clarity and consistency. In particular, on_success_callback is no longer executed when a task is marked as SKIPPED, aligning it more closely with expected semantics.
Several default configuration values have been updated in Airflow 3.0 to better reflect modern usage patterns and simplify onboarding:
catchup_by_default is now set to False by default. DAGs will not automatically backfill unless explicitly configured to do so.
create_cron_data_intervals is now set to False by default. As a result, cron expressions will be interpreted using the CronTriggerTimetable instead of the legacy CronDataIntervalTimetable. This only affects DAGs that pass a bare cron string to schedule=; DAGs that pass an explicit timetable instance are unaffected. If you rely on the data interval semantics (data_interval_start / data_interval_end, or templated values like ds / ts derived from logical_date), set create_cron_data_intervals=True explicitly before the upgrade. Flipping the value later, after Airflow 3 DAG runs already exist, will skip one scheduled run on each affected DAG to avoid colliding with the previous run's logical_date.
SimpleAuthManager is now the default auth_manager. To continue using Flask AppBuilder-based authentication, install the apache-airflow-providers-fab provider and explicitly set auth_manager = airflow.providers.fab.auth_manager.FabAuthManager.
These changes represent the most significant evolution of the Airflow platform since the release of 2.0 — setting the stage for more scalable, event-driven, and language-agnostic orchestration in the years ahead.
Airflow 3.0 introduces several important improvements and behavior changes in how DAGs and tasks are scheduled, prioritized, and executed.
Airflow 3.0 now requires the standalone DAG processor to parse DAGs. This dedicated process improves scheduler performance, isolation, and observability. It also simplifies architecture by clearly separating DAG parsing from scheduling logic. This change may affect custom deployments that previously used embedded DAG parsing.
The priority_weight value on a task is now capped by the number of available pool slots. This ensures that resource availability remains the primary constraint in task execution order, preventing high-priority tasks from starving others when resource contention exists.
Teardown tasks will now be executed even when a DAG run is terminated early. This ensures that cleanup logic is respected, improving reliability for workflows that use teardown tasks to manage ephemeral infrastructure, temporary files, or downstream notifications.
Scheduler components now use run_with_db_retries to handle transient database issues more gracefully. This enhances Airflow's fault tolerance in high-volume environments and reduces the likelihood of scheduler restarts due to temporary database connection problems.
Airflow 3.0 fixes a bug that caused incorrect task statistics to be reported for dynamic task mapping. Stats now accurately reflect the number of mapped task instances and their statuses, improving observability and debugging for dynamic workflows.
SequentialExecutor was primarily used for local testing but is now redundant, as LocalExecutor supports SQLite with WAL mode and provides better performance with parallel execution. Users should switch to LocalExecutor or CeleryExecutor as alternatives.
Airflow 3.0 includes several changes that improve consistency, clarity, and long-term stability for DAG authors.
Airflow 3.0 introduces a new, stable public API for DAG authoring under the airflow.sdk namespace, available via the apache-airflow-task-sdk package.
The goal of this change is to decouple DAG authoring from Airflow internals (Scheduler, API Server, etc.), providing a forward-compatible, stable interface for writing and maintaining DAGs across Airflow versions.
DAG authors should now import core constructs from airflow.sdk rather than internal modules.
Key Imports from airflow.sdk:
Classes:
Asset
BaseNotifier
BaseOperator
BaseOperatorLink
BaseSensorOperator
Connection
Context
DAG
EdgeModifier
Label
ObjectStoragePath
Param
TaskGroup
Variable
Decorators and Functions:
@asset
@dag
@setup
@task
@task_group
@teardown
chain
chain_linear
cross_downstream
get_current_context
get_parsing_context
For an exhaustive list of available classes, decorators, and functions, check airflow.sdk.__all__.
All DAGs should update imports to use airflow.sdk instead of referencing internal Airflow modules directly. Legacy import paths (e.g., airflow.models.dag.DAG, airflow.decorator.task) are deprecated and will be removed in a future Airflow version. Some additional utilities and helper functions that DAGs sometimes use from airflow.utils.* and others will be progressively migrated to the Task SDK in future minor releases.
These future changes aim to complete the decoupling of DAG authoring constructs from internal Airflow services. DAG authors should expect continued improvements to airflow.sdk with no backwards-incompatible changes to existing constructs.
For example, update:
# Old (Airflow 2.x)
from airflow.models import DAG
from airflow.decorators import task
# New (Airflow 3.x)
from airflow.sdk import DAG, task
The DAG argument fail_stop has been renamed to fail_fast for improved clarity. This parameter controls whether a DAG run should immediately stop execution when a task fails. DAG authors should update any code referencing fail_stop to use the new name.
Several legacy context variables have been removed or may no longer be available in certain types of DAG runs, including:
conf
execution_date
dag_run.external_trigger
In asset-triggered and manually triggered DAG runs with logical_date=None, data interval fields such as data_interval_start and data_interval_end may not be present in the task context. DAG authors should use explicit references such as dag_run.logical_date and conditionally check for the presence of interval-related fields where applicable.
Internal task context functions such as get_parsing_context have been moved to a more appropriate location (e.g., airflow.models.taskcontext). DAG authors using these utilities directly should update import paths accordingly.
The TriggerRule.ALWAYS rule can no longer be used with teardown tasks or tasks that are expected to honor upstream dependency semantics. DAG authors should ensure that teardown logic is defined with the appropriate trigger rules for consistent task resolution behavior.
A new utility function, create_asset_aliases(), allows DAG authors to define reusable aliases for frequently referenced Assets. This improves modularity and reuse across DAG files and is particularly helpful for teams adopting asset-centric DAGs.
The Operator Extra links, which can be defined either via plugins or custom operators now do not execute any user code in the Airflow UI, but instead push the "full" links to XCom backend and the link is fetched from the XCom backend when viewing task details, for example from grid view.
Example for users with custom links class:
@attr.s(auto_attribs=True)
class CustomBaseIndexOpLink(BaseOperatorLink):
"""Custom Operator Link for Google BigQuery Console."""
index: int = attr.ib()
@property
def name(self) -> str:
return f"BigQuery Console #{self.index + 1}"
@property
def xcom_key(self) -> str:
return f"bigquery_{self.index + 1}"
def get_link(self, operator, *, ti_key):
search_queries = XCom.get_one(
task_id=ti_key.task_id, dag_id=ti_key.dag_id, run_id=ti_key.run_id, key="search_query"
)
return f"https://console.cloud.google.com/bigquery?j={search_query}"
The link has an xcom_key defined, which is how it will be stored in the XCOM backend, with key as xcom_key and value as the entire link, this case: https://console.cloud.google.com/bigquery?j=search
Operator (including Sensors), Executors & Hooks can no longer be registered or imported via Airflow's plugin mechanism. These types of classes are just treated as plain Python classes by Airflow, so there is no need to register them with Airflow. They can be imported directly from their respective provider packages.
Before:
from airflow.hooks.my_plugin import MyHook
You should instead import it as:
from my_plugin import MyHook
Airflow 3.0 expands the types of DAGs that can be expressed by removing the constraint that each DAG run must correspond to a unique data interval. This change, introduced in AIP-83, enables support for workflows that don't operate on a fixed schedule — such as model training, hyperparameter tuning, and inference tasks.
These ML- and AI-oriented DAGs often run ad hoc, are triggered by external systems, or need to execute multiple times with different parameters over the same dataset. By allowing multiple DAG runs with logical_date=None, Airflow now supports these scenarios natively without requiring workarounds.
Airflow 3.0 introduces several configuration and interface updates that improve consistency, clarify ownership of core utilities, and remove legacy behaviors that were no longer aligned with modern usage patterns.
Airflow no longer silently updates configuration options that retain deprecated default values. Users are now required to explicitly set any config values that differ from the current defaults. This change improves transparency and prevents unintentional behavior changes during upgrades.
Several configuration defaults have changed in Airflow 3.0 to better reflect modern usage patterns:
The default value of catchup_by_default is now False. DAGs will not backfill missed intervals unless explicitly configured to do so.
The default value of create_cron_data_intervals is now False. Cron expressions are now interpreted using the CronTriggerTimetable instead of the legacy CronDataIntervalTimetable. This change simplifies interval logic and aligns with the future direction of Airflow's scheduling system. Set this flag explicitly before upgrading from Airflow 2 if you rely on data interval semantics; flipping it later (after Airflow 3 DAG runs exist) will skip one scheduled run per affected DAG.
Several core components have been moved to more intuitive or stable locations:
The SecretsMasker class has been relocated to airflow.sdk.execution_time.secrets_masker.
The ObjectStoragePath utility previously located under airflow.io is now available via airflow.sdk.
These changes simplify imports and reflect broader efforts to stabilize utility interfaces across the Airflow codebase.
Asset event mappings in the task context are improved to better support asset use cases, including new features introduced in AIP-74.
Events of an asset or asset alias are now accessed directly by a concrete object to avoid ambiguity. Using a str to access events is no longer supported. Use an Asset or AssetAlias object, or Asset.ref to refer to an entity explicitly instead, such as:
outlet_events[Asset.ref(name="myasset")] # Get events for asset named "myasset". outlet_events[AssetAlias(name="myalias")] # Get events for asset alias named "myalias".
Alternatively, two helpers for_asset and for_asset_alias are added as shortcuts:
outlet_events.for_asset(name="myasset") # Get events for asset named "myasset". outlet_events.for_asset_alias(name="myalias") # Get events for asset alias named "myalias".
The internal representation of asset event triggers now also includes an explicit uri field, simplifying traceability and aligning with the broader asset-aware execution model introduced in Airflow 3.0. DAG authors interacting directly with inlet_events may need to update logic that assumes the previous structure.
In Airflow 2, the xcom_pull() method allowed pulling XComs by key without specifying task_ids, despite the fact that the underlying DB model defines task_id as part of the XCom primary key. This created ambiguity: if two tasks pushed XComs with the same key, xcom_pull() would pull whichever one happened to be first, leading to unpredictable behavior.
Airflow 3 resolves this inconsistency by requiring task_ids when pulling by key. This change aligns with the task-scoped nature of XComs as defined by the schema, ensuring predictable and consistent behavior.
DAG Authors should update their dags to use task_ids if their dags used xcom_pull without task_ids such as:
kwargs["ti"].xcom_pull(key="key")
Should be updated to:
kwargs["ti"].xcom_pull(task_ids="task1", key="key")
As part of the deprecation cleanup, several legacy configuration options have been removed. These include:
[scheduler] allow_trigger_in_future
[scheduler] use_job_schedule
[scheduler] use_local_tz
[scheduler] processor_poll_interval
[logging] dag_processor_manager_log_location
[logging] dag_processor_manager_log_stdout
[logging] log_processor_filename_template
All the webserver configurations have also been removed since API server now replaces webserver, so the configurations like below have no effect:
[webserver] allow_raw_html_descriptions
[webserver] cookie_samesite
[webserver] error_logfile
[webserver] access_logformat
[webserver] web_server_master_timeout
etc
Several configuration options previously located under the [webserver] section have been moved to the new ``[api]`` section. The following configuration keys have been moved:
[webserver] web_server_host → [api] host
[webserver] web_server_port → [api] port
[webserver] workers → [api] workers
[webserver] web_server_worker_timeout → [api] worker_timeout
[webserver] web_server_ssl_cert → [api] ssl_cert
[webserver] web_server_ssl_key → [api] ssl_key
[webserver] access_logfile → [api] access_logfile
The following DAG parsing configuration options were moved to the new ``[dag_processor]`` section:
[core] dag_file_processor_timeout → [dag_processor] dag_file_processor_timeout
[scheduler] parsing_processes → [dag_processor] parsing_processes
[scheduler] file_parsing_sort_mode → [dag_processor] file_parsing_sort_mode
[scheduler] max_callbacks_per_loop → [dag_processor] max_callbacks_per_loop
[scheduler] min_file_process_interval → [dag_processor] min_file_process_interval
[scheduler] stale_dag_threshold → [dag_processor] stale_dag_threshold
[scheduler] print_stats_interval → [dag_processor] print_stats_interval
Users should review their airflow.cfg files or use the airflow config lint command to identify outdated or removed options.
Airflow 3.0 includes improved support for upgrade validation. Use the following tools to proactively catch incompatible configs or deprecated usage patterns:
airflow config lint: Identifies removed or invalid config keys
ruff check --select AIR30 --preview: Flags removed interfaces and common migration issues
Airflow 3.0 introduces changes to both the CLI and REST API interfaces to better align with service-oriented deployments and event-driven workflows.
The Airflow CLI has been split into two distinct interfaces:
The core airflow CLI now handles only local functionality (e.g., airflow tasks test, airflow dags list).
Remote functionality, including triggering DAGs or managing connections in service-mode environments, is now handled by a separate CLI called airflowctl, distributed via the apache-airflow-client package.
This change improves security and modularity for deployments that use Airflow in a distributed or API-first context.
The legacy REST API v1, previously built with Connexion and Marshmallow, has been replaced by a modern FastAPI-based REST API v2.
This new implementation improves performance, aligns more closely with web standards, and provides a consistent developer experience across the API and UI.
Key changes include stricter validation (422 errors instead of 400), the removal of the execution_date parameter in favor of logical_date, and more consistent query parameter handling.
The v2 API is now the stable, fully supported interface for programmatic access to Airflow, and also powers the new UI - achieving full feature parity between the UI and API.
For details, see the Airflow REST API v2 documentation.
The behavior of the POST /dags/{dag_id}/dagRuns endpoint has changed. If a logical_date is not explicitly provided when triggering a DAG via the REST API, it now defaults to None.
This aligns with event-driven DAGs and manual runs in Airflow 3.0, but may break backward compatibility with scripts or tools that previously relied on Airflow auto-generating a timestamped logical_date.
Several deprecated CLI arguments and commands that were marked for removal in earlier versions have now been cleaned up in Airflow 3.0. Run airflow --help to review the current set of available commands and arguments.
Deprecated --ignore-depends-on-past cli option is replaced by --depends-on-past ignore.
--tree flag for airflow tasks list command is removed. The format of the output with that flag can be expensive to generate and extremely large, depending on the DAG. airflow dag show is a better way to visualize the relationship of tasks in a DAG.
Changing dag_id from flag (-d, --dag-id) to a positional argument in the dags list-runs CLI command.
The airflow db init and airflow db upgrade commands have been removed. Use airflow db migrate instead to initialize or migrate the metadata database. If you would like to create default connections use airflow connections create-default-connections.
airflow api-server has replaced airflow webserver cli command.
Airflow 3.0 completes the migration of several core operators, sensors, hooks, and triggers into the new apache-airflow-providers-standard package. This package now includes commonly used components such as:
PythonOperator, BashOperator
ExternalTaskSensor, FileSensor
ShortCircuitOperator, LatestOnlyOperator
SubprocessHook, FilesystemHook
DateTimeTrigger, TimeDeltaTrigger, FileTrigger
These operators, sensors, hooks, and triggers were previously bundled inside airflow-core but are now treated as provider-managed components to improve modularity, testability, and lifecycle independence.
This change enables more consistent versioning across providers and prepares Airflow for a future where all integrations — including "standard" ones — follow the same interface model.
To maintain compatibility with existing DAGs, the apache-airflow-providers-standard package is installable on both Airflow 2.x and 3.x. Users upgrading from Airflow 2.x are encouraged to begin updating import paths and testing provider installation in advance of the upgrade.
Legacy imports such as airflow.operators.python.PythonOperator are deprecated and will be removed soon. They should be replaced with:
from airflow.providers.standard.operators.python import PythonOperator
The SimpleHttpOperator has been migrated to apache-airflow-providers-http and renamed to HttpOperator
Airflow 3.0 introduces a modernized user experience that complements the new React-based UI architecture (see Significant Changes). Several areas of the interface have been enhanced to improve visibility, consistency, and navigability.
The Airflow Home page now provides a high-level operational overview of your environment. It includes health checks for core components (Scheduler, Triggerer, DAG Processor), summary stats for DAG and task instance states, and a real-time feed of asset-triggered events. This view helps users quickly identify pipeline health, recent activity, and potential failures.
The DAG List page has been refreshed with a cleaner layout and improved responsiveness. Users can browse DAGs by name, tags, or owners. While full-text search has not yet been integrated, filters and navigation have been refined for clarity in large deployments.
The Graph and Grid views now display task information in the context of the DAG version that was used at runtime. This improves traceability for DAGs that evolve over time and provides more accurate debugging of historical runs.
The Graph view now supports visualizing the full chain of asset and task dependencies, including assets consumed or produced across DAG boundaries. This allows users to inspect upstream and downstream lineage in a unified view, making it easier to trace data flows, debug triggering behavior, and understand conditional dependencies between assets and tasks.
The "Code" tab now displays the exact DAG source as parsed by the scheduler for the selected DAG version. This allows users to inspect the precise code that was executed, even for historical runs, and helps debug issues related to versioned DAG changes.
Task log access has been streamlined across views. Logs are now easier to access from both the Grid and Task Instance pages, with cleaner formatting and reduced visual noise.
New UI components support asset-centric DAGs and backfill workflows:
Asset definitions are now visible from the DAG details page, allowing users to inspect upstream and downstream asset relationships.
Backfills can be triggered and monitored directly from the UI, including support for scheduler-managed backfills introduced in Airflow 3.0.
These improvements make Airflow more accessible to operators, data engineers, and stakeholders working across both time-based and event-driven workflows.
A number of deprecated features, modules, and interfaces have been removed in Airflow 3.0, completing long-standing migrations and cleanups.
Users are encouraged to review the following removals to ensure compatibility:
SubDag support has been removed entirely, including the SubDagOperator, related CLI and API interfaces. TaskGroups are now the recommended alternative for nested DAG structures.
SLAs have been removed: The legacy SLA feature, including SLA callbacks and metrics, has been removed. A more flexible replacement mechanism, DeadlineAlerts, is planned for a future version of Airflow. Users who relied on SLA-based notifications should consider implementing custom alerting using task-level success/failure hooks or external monitoring integrations.
Pickling support has been removed: All legacy features related to DAG pickling have been fully removed. This includes the PickleDag CLI/API, as well as implicit behaviors around store_serialized_dags = False. DAGs must now be serialized using the JSON-based serialization system. Ensure any custom Python objects used in DAGs are JSON-serializable.
Context parameter cleanup: Several previously available context variables have been removed from the task execution context, including conf, execution_date, and dag_run.external_trigger. These values are either no longer applicable or have been renamed (e.g., use dag_run.logical_date instead of execution_date). DAG authors should ensure that templated fields and Python callables do not reference these deprecated keys.
Deprecated core imports have been fully removed. Any use of airflow.operators.*, airflow.hooks.*, or similar legacy import paths should be updated to import from their respective providers.
Configuration cleanup: Several legacy config options have been removed, including:
scheduler.allow_trigger_in_future: DAG runs can no longer be triggered with a future logical date. Use logical_date=None instead.
scheduler.use_job_schedule and scheduler.use_local_tz have also been removed. These options were deprecated and no longer had any effect.
Deprecated utility methods such as those in airflow.utils.helpers, airflow.utils.process_utils, and airflow.utils.timezone have been removed. Equivalent functionality can now be found in the standard Python library or Airflow provider modules.
Removal of deprecated CLI flags and behavior: Several CLI entrypoints and arguments that were marked for removal in earlier versions have been cleaned up.
To assist with the upgrade, tools like ruff (e.g., rule AIR302) and airflow config lint can help identify obsolete imports and configuration keys. These utilities are recommended for locating and resolving common incompatibilities during migration. Please see Upgrade Guide for more information.
The following table summarizes user-facing features removed in 3.0 and their recommended replacements. Not all of these are called out individually above.
Feature |
Replacement / Notes |
|---|---|
SubDagOperator / SubDAGs |
Use TaskGroups |
SLA callbacks / metrics |
Deadline Alerts (planned post-3.0) |
DAG Pickling |
Use JSON serialization; pickling is no longer supported |
Xcom Pickling |
Use custom Xcom backend; pickling is no longer supported |
execution_date context var |
Use dag_run.logical_date |
conf and dag_run.external_trigger |
Removed from context; use DAG params or dag_run APIs |
Core EmailOperator |
Use EmailOperator from the smtp provider |
none_failed_or_skipped rule |
Use none_failed_min_one_success |
dummy trigger rule |
Use always |
fail_stop argument |
Use fail_fast |
store_serialized_dags=False |
DAGs are always serialized; config has no effect |
Deprecated core imports |
Import from appropriate provider package |
SequentialExecutor & DebugExecutor |
Use LocalExecutor for testing |
.airflowignore regex |
Uses glob syntax by default |
Airflow 3 was designed with migration in mind. Many Airflow 2 DAGs will work without changes, especially if deprecation warnings were addressed in earlier releases. To support the upgrade, Airflow 3 includes validation tools such as ruff and airflow config update, as well as a simplified startup model.
For a step-by-step upgrade process, see the Upgrade Guide.
To upgrade to Airflow 3.0, you must be running Airflow 2.7 or later.
Airflow 3.0 supports the following Python versions:
Python 3.9
Python 3.10
Python 3.11
Python 3.12
Earlier versions of Airflow or Python are not supported due to architectural changes and updated dependency requirements.
Airflow now includes a Ruff-based linter with custom rules to detect DAG patterns and interfaces that are no longer compatible with Airflow 3.0. These checks are packaged under the AIR30x rule series. Example usage:
ruff check dags/ --select AIR301 --preview
ruff check dags/ --select AIR301 --fix --preview
These checks can automatically fix many common issues such as renamed arguments, removed imports, or legacy context variable usage.
Airflow 3.0 introduces a new utility to validate and upgrade your Airflow configuration file:
airflow config update
airflow config update --fix
This utility detects removed or deprecated configuration options and, if desired, updates them in-place.
Additional validation is available via:
airflow config lint
This command surfaces obsolete configuration keys and helps align your environment with Airflow 3.0 requirements.
As with previous major releases, the Airflow 3.0 upgrade includes schema changes to the metadata database. Before upgrading, it is strongly recommended that you back up your database and optionally run:
airflow db clean
to remove old task instance, log, or XCom data. To apply the new schema:
airflow db migrate
Airflow components are now started explicitly. For example:
airflow api-server # Replaces airflow webserver
airflow dag-processor # Required in all environments
These changes reflect Airflow's new service-oriented architecture.
Upgrade Guide
Airflow 3.0 represents more than a year of collaboration across hundreds of contributors and dozens of organizations. We thank everyone who helped shape this release through design discussions, code contributions, testing, documentation, and community feedback. For full details, migration guidance, and upgrade best practices, refer to the official Upgrade Guide and join the conversation on the Airflow dev and user mailing lists.
Release Date: 2022-06-13
Note
This release of provider is only available for Airflow 2.2+ as explained in the Apache Airflow providers support policy .
Remove 'xcom_push' from 'DockerOperator' (#23981)
docker new system test (#23167)
Note
This release of provider is only available for Airflow 2.2+ as explained in the Apache Airflow providers support policy.
Remove 'xcom_push' from 'DockerOperator' (#23981)
docker new system test (#23167)
Nothing published for this version
Nothing published for this version
Add deprecation info to the Airflow modules and classes docstring
As of now, Python 3.7 is no longer supported by the Python community. Therefore, to use Airflow 2.7.0, you must ensure your Python version is either 3.8, 3.9, 3.10, or 3.11.
The old Graph View is removed. The new Graph View is the default view now.
If you are using dag_run.conf dictionary and web UI JSON entry to run your DAG you should either:
Add params to your DAG <https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/params.html#use-params-to-provide-a-trigger-ui-form>_show_trigger_form_if_no_params to bring back old behaviourInstead, you should use "airflow db migrate" command to create or upgrade database. This command will not create default connections. In order to create default connections you need to run "airflow connections create-default-connections" explicitly, after running "airflow db migrate".
The "default" context is Python's default_ssl_contest instead of previously used "none". The
default_ssl_context provides a balance between security and compatibility but in some cases,
when certificates are old, self-signed or misconfigured, it might not work. This can be configured
by setting "ssl_context" in "email" configuration of Airflow.
Setting it to "none" brings back the "none" setting that was used in Airflow 2.6 and before, but it is not recommended due to security reasons ad this setting disables validation of certificates and allows MITM attacks.
For security reasons, the test connection functionality is disabled by default across Airflow UI,
API and CLI. The availability of the functionality can be controlled by the
test_connection flag in the core section of the Airflow
configuration (airflow.cfg). It can also be controlled by the
environment variable AIRFLOW__CORE__TEST_CONNECTION.
The following values are accepted for this config param:
Disabled: Disables the test connection functionality and
disables the Test Connection button in the UI.This is also the default value set in the Airflow configuration.
2. Enabled: Enables the test connection functionality and
activates the Test Connection button in the UI.
Hidden: Disables the test connection functionality and
hides the Test Connection button in UI.For more information on capabilities of users, see the documentation: https://airflow.apache.org/docs/apache-airflow/stable/security/security_model.html#capabilities-of-authenticated-ui-users It is strongly advised to not enable the feature until you make sure that only highly trusted UI/API users have "edit connection" permissions.
xcomEntries API disables support for the deserialize flag by default (#32176)For security reasons, the /dags/*/dagRuns/*/taskInstances/*/xcomEntries/*
API endpoint now disables the deserialize option to deserialize arbitrary
XCom values in the webserver. For backward compatibility, server admins may set
the [api] enable_xcom_deserialize_support config to True to enable the
flag and restore backward compatibility.
However, it is strongly advised to not enable the feature, and perform deserialization at the client side instead.
Default name of the Celery application changed from airflow.executors.celery_executor to airflow.providers.celery.executors.celery_executor.
You should change both your configuration and Health check command to use the new name:
celery_app_name configuration in celery section) use airflow.providers.celery.executors.celery_executorairflow.providers.celery.executors.celery_executor.appscheduler.max_tis_per_query is changed from 512 to 16 (#32572)This change is expected to make the Scheduler more responsive.
scheduler.max_tis_per_query needs to be lower than core.parallelism.
If both were left to their default value previously, the effective default value of scheduler.max_tis_per_query was 32
(because it was capped at core.parallelism).
To keep the behavior as close as possible to the old config, one can set scheduler.max_tis_per_query = 0,
in which case it'll always use the value of core.parallelism.
In order to use the executors, you need to install the providers:
apache-airflow-providers-celery package >= 3.3.0apache-airflow-providers-cncf-kubernetes package >= 7.4.0apache-airflow-providers-daskexecutor package in any versionYou can achieve it also by installing airflow with [celery], [cncf.kubernetes], [daskexecutor] extras respectively.
Users who base their images on the apache/airflow reference image (not slim) should be unaffected - the base
reference image comes with all the three providers installed.
This index seems to have great positive effect in a setup with tens of millions such rows.
BranchExternalPythonOperator (#32787, #33360)Per-LocalTaskJob Configuration (#32313)AirflowClusterPolicySkipDag exception (#32013)reactflow for datasets graph (#31775)chain which doesn't require matched lists (#31927)--retry and --retry-delay to airflow db check (#31836)section query param in get config rest API (#30936)Scheduled->Queued->Running task state transition times (#30612)db upgrade to db migrate and add connections create-default-connections (#32810, #33136)<= parallelism (#32572)isdisjoint instead of not intersection (#32616)dag_processor status. (#32382)[triggers.running] (#32050)TriggerDagRunOperator: Add wait_for_completion to template_fields (#31122)PythonVirtualenvOperator termination log in alert (#31747)airflow db commands to SQLAlchemy 2.0 style (#31486)validators into their own modules (#30802)get_log api (#30729)Gantt chart: Use earliest/oldest ti dates if different than dag run start/end (#33215)virtualenv detection for Python virtualenv operator (#33223)chmod airflow.cfg (#33118)max_active_runs reached its upper limit. (#31414)get_task_instances query (#33054)$ref (#32887)PythonOperator sub-classes extend its decorator (#32845)virtualenv is installed in PythonVirtualenvOperator (#32939)__iter__ in is_container() (#32850)dagRunTimeout (#32565)/blocked endpoint (#32571)cli.dags.trigger command output (#32548)whitespaces from airflow connections form (#32292)readonly property in our API (#32510)resizer wouldn't expanse grid view (#31581)type_ arg to drop_constraint (#31306)drop_constraint call in migrations (#31302)requirepass redis sentinel (#30352)/config (#31057)dag_processing (#33161)Pydantic to < 2.0.0 (#33235)cncf.kubernetes provider (#32767, #32891)pydocstyle check - core Airflow only (#31297)1.2.3 to 1.2.4 in /airflow/www (#32680)6.3.0 to 6.3.1 in /airflow/www (#32506)4.18.0 (#32445)stylelint from 13.13.1 to 15.10.1 in /airflow/www (#32435)4.0.0 to 4.1.3 in /airflow/www (#32443)Pydantic 2 (#32366)enums (#31735)0.272 (#31966)asynctest (#31664)2.0 style (#31569, #31772, #32350, #32339, #32474, #32645)3.7 support (#30963)0.0.262 (#30809)1.2.0 (#30687)DAGRun / DAG / Task in templates-ref.rst (#33013)Release Date: 2022-05-16
Add 'device_requests' parameter to 'DockerOperator' (#23554)
Fix new MyPy errors in main (#22884)
Add 'device_requests' parameter to 'DockerOperator' (#23554)
Fix new MyPy errors in main (#22884)
Nothing published for this version
This is potentially a breaking change for any custom trigger implementations that override the cleanup() method and uses synchronous code, however usi…
Default setting handles case where impersonation is needed and both users (airflow and the impersonated user)
have the same group set as main group. Previously the default was also other-writeable and the user might choose
to use the other-writeable setting if they wish by configuring file_task_handler_new_folder_permissions
and file_task_handler_new_file_permissions in logging section.
This stops SLA callbacks from keeping the dag processor manager permanently busy. It means reduced CPU, and fixes issues where SLAs stop the system from seeing changes to existing dag files. Additional metrics added to help track queue state.
cleanup() method in BaseTrigger is now defined as asynchronous (following async/await) pattern (#30152).This is potentially a breaking change for any custom trigger implementations that override the cleanup()
method and uses synchronous code, however using synchronous operations in cleanup was technically wrong,
because the method was executed in the main loop of the Triggerer and it was introducing unnecessary delays
impacting other triggers. The change is unlikely to affect any existing trigger implementations.
scheduler.tasks.running no longer exist (#30374)The gauge has never been working and its value has always been 0. Having an accurate value for this metric is complex so it has been decided that removing this gauge makes more sense than fixing it with no certainty of the correctness of its value.
task_queued_timeout config (#30375)Logic for handling tasks stuck in the queued state has been consolidated, and the all configurations
responsible for timing out stuck queued tasks have been deprecated and merged into
[scheduler] task_queued_timeout. The configurations that have been deprecated are
[kubernetes] worker_pods_pending_timeout, [celery] stalled_task_timeout, and
[celery] task_adoption_timeout. If any of these configurations are set, the longest timeout will be
respected. For example, if [celery] stalled_task_timeout is 1200, and [scheduler] task_queued_timeout
is 600, Airflow will set [scheduler] task_queued_timeout to 1200.
The configurations view now only displays the running configuration. Previously, the default configuration
was displayed at the top but it was not obvious whether this default configuration was overridden or not.
Subsequently, the non-documented endpoint /configuration?raw=true is deprecated and will be removed in
Airflow 3.0. The HTTP response now returns an additional Deprecation header. The /config endpoint on
the REST API is the standard way to fetch Airflow configuration programmatically.
ExternalTaskSensor now has an explicit skipped_states list
Maximum retry task delay is set to be 24h (86400s) by default. You can change it globally via core.max_task_retry_delay
parameter.
The Hive Macros (hive.max_partition, hive.closest_ds_partition) are available only when Hive Provider is
installed. Please install Hive Provider > 5.1.0 when using those macros.
max_active_tis_per_dagrun for Dynamic Task Mapping (#29094)TriggerDagRunOperator (#30292)Blocklist to disable specific metric tags or metric names (#29881)check_migrations config (#29714)cli.dags.trigger (#29224)db export-archived command. (#29485)airflow db drop-archived command (#29309)FileTrigger (#29265)connections import CLI command (#28738)AIP-51 <https://github.com/apache/airflow/pulls?q=is%3Apr+is%3Amerged+label%3AAIP-51+milestone%3A%22Airflow+2.6.0%22>_)UX in grid view (#30373)select() to new style (#30515)metrics_*_list (#30174)on_*_callback/sla_miss_callbacks (#28469)renamed and previous_name in config sections (#28324)triggerer status (#27755)too old resource version exception by retrieving the latest resource_version (#30425)TriggerDagRunOperator with deferrable parameter (#30406)example_sensor_decorator DAG (#30513)skip_exit_code in BashOperator (#30734)scheduler.tasks.running (#30374)/airflow/www (#30568)/airflow/www (#30319)/airflow/www (#30316)dag.fileloc instead of dag.full_filepath in exception message (#30610)importlib-metadata backport to < 5.0.0 (#29924)importlib.metadata to get Version for speed (#29723)db export-cleaned to db export-archived (#29450)freezegun with time-machine (#28193)airflow/kubernetes/* (#28212)audit_logs.rst (#30405)*_lookup_pattern parameters (#29580)Release Date: 2022-04-11
Add timeout parameter to 'DockerOperator' (#22502)
Nothing published for this version
…time and no timezone was specified) but we raise deprecation warning.
In case of API calls, it was possible that "+" passed as part of the date-time fields were not URL-encoded, and
such date-time fields could pass validation. Such date-time parameters should now be URL-encoded (as %2B).
In case of parameters, we still allow IS8601-compliant date-time (so for example it is possible that
' ' was used instead of T separating date from time and no timezone was specified) but we raise
deprecation warning.
[webserver] expose_hostname changed to False (#29547)The default for [webserver] expose_hostname has been set to False, instead of True. This means administrators must opt-in to expose webserver hostnames to end users.
/dagRuns API should 404 if dag not active (#29860)openapi spec responses by adding additional return type (#29600)prev_logical_date variable offset-aware (#29454)Edgemodifier refactoring w/ labels in TaskGroup edge case (#29410)airflow connections add (#28922)undici from 5.9.1 to 5.19.1 (#29583)v67.2.0 (#29465)ua-parser-js from 0.7.31 to 0.7.33 in /airflow/www (#29172)pytest (#29086)run_id url param when linking to graph/gantt views (#29066)python_callable (#28932)swagger-ui-dist from 3.52.0 to 4.1.3 in /airflow/www (#28824)importlib-metadata backport to < 5.0.0 (#29924, #30069)merge_data() task (#29158)notes param from TriggerDagRunOperator docstring (#29298)schedule param rather than timetable in Timetables docs (#29255)Release Date: 2022-03-26
Fix mistakenly added install_requires for all providers (#22382)
Correct 'multiple_outputs' param descriptions mentioning lists/tuples (#22371)
Nothing published for this version
Fix masking of non-sensitive environment variables
swagger-ui-dist via npm package (#28788)UIAlert should_show when AUTH_ROLE_PUBLIC set (#28781)external_task_ids of ExternalTaskSensor (#28692)DetachedInstanceError when finding zombies in Dag Parsing process (#28198)divs to fix dagid copy nit on dag.html (#28643)setNote endpoints under TaskInstance in OpenAPI (#28566)CronTriggerTimetable (#28532)ensure_ascii=False in trigger dag run API (#28451)ti._try_number for deferred and up_for_reschedule tasks (#26993)callModal from dag.js (#28410)monkeypatching via environment variable (#28283)LazyXComAccess (#28191)@dag decorator are reported in dag file (#28153)dagbag_size metric decreases when files are deleted (#28135)airflow.api.auth.backend.session to backend sessions in compose (#28094)next_dagruns_to_examine, add MySQL index hint (#27821)dnspython after eventlet got fixed (#29004)dnspython to < 2.3.0 until eventlet incompatibility is solved (#28962)SQLAlchemy to below 2.0 (#28725)json5 from 1.0.1 to 1.0.2 in /airflow/www (#28715)Enums (#28627)Connection.get_extra type (#28594)conf.get* from the right source location (#28543)purge_inactive_dag_warnings (#28481)test_task_command to Pytest and unquarantine tests in it (#28247)0.2.0 to 0.2.2 in /airflow/www (#28080)subgraph logic (#27987)map_index (#27904)LocalTaskJob (#27381)Release Date: 2022-03-19
Avoid trying to kill container when it did not succeed for Docker (#22145)
Add Trove classifiers in PyPI (Framework :: Apache Airflow :: Provider)
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →