Variables, XCom, and Parameters

Purpose and Scope

Airflow DAGs often need runtime values that are not hard-coded into Python files. This page explains three related concepts used for that job: Variables, XComs, and Params. A Variable is a globally named runtime configuration value stored and managed by Airflow. An XCom is task-to-task data exchange tied to a specific DAG run and task context. A Param is a user-facing or DAG-defined parameter used to influence a DAG run. Together they let authors separate reusable workflow code from operational inputs, task outputs, and trigger-time choices.

The repository evidence for this page is strongest around Variables, so the implementation mapping focuses on how Variables are represented in the UI and public FastAPI API. The official documentation places Variables alongside XComs and Params in the Core Concepts navigation, which is a useful mental model: choose Variables for installation-level or environment-level values, XComs for values produced by one task and consumed by another in the same workflow execution, and Params for values supplied to a DAG or task at parse time or run trigger time. Sources: airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables.py, airflow-core/src/airflow/api_fastapi/core_api/routes/public/variables.py

Relevant Source Files

  • docs/images/documentation_architecture.py - Generates the documentation architecture diagram that explains how Airflow package docs are published from the repository to the live documentation site, giving context for why the official Variables, XComs, and Params pages mirror source-backed behavior.
  • airflow-core/src/airflow/ui/src/pages/Variables/index.tsx - Exposes the Variables page component from the React UI package, showing that Variables are a first-class administrative surface in the Airflow web UI.
  • airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables.py - Defines public API serializers for Variable responses, request bodies, partial updates, collections, and import results.
  • airflow-core/src/airflow/api_fastapi/core_api/routes/public/variables.py - Defines the public FastAPI router for Variable endpoints, including individual lookup, listing, deletion, access checks, filtering, sorting, and database interaction.
  • airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py - Implements service-level update and bulk-operation behavior for Variables, including key validation, update masks, validation errors, and database lookups.

Core Runtime Value Primitives

Use Variables when a value belongs to the Airflow environment rather than to one DAG run. Examples include feature flags, external dataset names, tenant-level defaults, or non-secret configuration that many DAGs read. Variables have keys, values, optional descriptions, encryption state in responses, and optional team ownership metadata. The public API models make this explicit through VariableResponse and VariableBody, where key, value, description, and team_name form the visible contract. Sources: airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables.py

Use XComs when the value is produced during execution and should travel with the task instance history. XCom-style data exchange is different from Variables because it is scoped to workflow execution rather than to the global Airflow installation. That distinction matters for reproducibility: a downstream task reading an upstream result should use the run-specific value that was produced for that run, not a mutable global setting that might be edited later. Treat XComs as execution artifacts and Variables as configuration.

Use Params when a DAG author wants a controlled input surface for a DAG run. Params are commonly the right place for user-selected values at trigger time, such as a date range, account identifier, mode, or threshold. They are more explicit than Variables because they are part of the DAG interface rather than ambient configuration. They are also different from XComs because they exist before task execution starts. In practice, Params help make a DAG run explainable: the run was launched with these declared inputs, tasks produced XCom outputs, and Variables supplied shared environment configuration.

Variables API Components

The Variable API is modeled with Pydantic types that separate response shape from request shape. VariableResponse exposes key, value through the internal alias val, description, is_encrypted, and team_name. Before a response is returned, the model validator attempts to parse the value as JSON and passes dictionaries through Airflow's secret redaction helper. If the value is not JSON, it still passes the string through the same redaction path. That design lets the API return useful values while reducing accidental exposure of sensitive-looking content. Sources: airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables.py

VariableBody is the write-side contract. It requires a key with the repository-wide ID_LEN maximum, accepts a JSON-compatible value, and supports optional description and team_name. The value field serializes under the database-facing alias val, keeping the public API readable while matching Airflow's existing model naming. The model also validates multi-team behavior: team_name can only be set when core.multi_team is enabled, otherwise validation raises a clear administrator-oriented error. Sources: airflow-core/src/airflow/api_fastapi/core_api/datamodels/variables.py

ComponentPublic contractImportant behavior
VariableResponsekey, value, description, is_encrypted, team_nameRedacts JSON and non-JSON values before response serialization
VariableBodykey, value, description, team_nameEnforces key length and multi-team configuration rules
VariableBodyPartialPartial form of VariableBodyUsed for update-mask validation in service logic
VariableCollectionResponsevariables, total_entriesRepresents paginated list responses
VariablesImportResponsecreated_variable_keys, import_count, created_countRepresents import operation results

Public Routes and Service Behavior

The public Variables router is registered with the Variable tag and the /variables prefix. The visible route code includes delete, get one, and list behavior. Individual reads query the metadata database by Variable.key and return a 404 HTTP exception when the key is missing. Deletion uses a SQLAlchemy delete statement directly, then checks the affected row count and raises the same not-found style error if nothing was removed. The route comments explain that these endpoints intentionally do not call Variable.get, Variable.set, or Variable.delete because those helpers are intended for task execution environments. Sources: airflow-core/src/airflow/api_fastapi/core_api/routes/public/variables.py

Listing Variables accepts common API controls such as limit, offset, order_by, key pattern search, key prefix pattern search, and a readable-variables security filter. Sorting is constrained to real Variable fields such as key, id, _val, description, is_encrypted, and team_name. Access control is enforced through dependencies such as requires_access_variable, requires_access_variable_bulk, and ReadableVariablesFilterDep, so API behavior is not just CRUD; it is filtered by the caller's authorization context. Sources: airflow-core/src/airflow/api_fastapi/core_api/routes/public/variables.py

Update behavior is handled in service code by update_orm_from_pydantic. The function requires the URI key and request body key to match, looks up the existing Variable, validates either the selected update-mask fields or the whole body, and treats key as a non-updateable field. If the Variable does not exist, it raises 404; if the body key disagrees with the URI, it raises 400. This makes Variable updates intentionally conservative: callers may change value-like metadata, but they cannot rename a Variable through a patch path. Sources: airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py

Authoring Guidance

For DAG authors, the most important decision is scoping. If a value should be stable across many runs and editable by an operator without changing DAG code, prefer a Variable. If a value is the output of a task and should be tied to the specific run that produced it, prefer XCom-style exchange. If a value should be declared as part of the DAG run contract, prefer Params. This separation prevents common maintenance problems, such as downstream tasks accidentally reading a newly edited Variable instead of the upstream result from the same run.

Variables should not become a replacement for secrets management or structured deployment configuration. The API response model includes encryption state and redaction because Airflow expects Variables to contain sensitive-looking data in some installations, but redaction is a safety layer, not a reason to put credentials everywhere. When a value is a credential, token, or connection detail, use the relevant secrets backend or Connection mechanism instead. When a value is an operator argument that changes per run, expose it as a Param so the run record remains understandable.

A practical workflow is to design each DAG with three columns of inputs. First, list deployment defaults that operators may change globally; those are candidates for Variables. Second, list values created by tasks, such as object keys, partition lists, counts, or validation results; those should be XComs or task return values in a TaskFlow-style DAG. Third, list user choices made when triggering or backfilling the DAG; those belong in Params. This small design pass makes the DAG easier to test, review, and debug later.

UI, Documentation, and Operational Signals

The React UI source exports a Variables page from the Variables page directory, which aligns with the official how-to documentation for managing Variables through Airflow's UI, CLI, and REST API. The checked-in export is small, but it is still a useful boundary: Variables are not only a Python authoring feature; they are an administrative object with a dedicated UI surface. That matters operationally because changes to global runtime configuration are usually made by humans and should be discoverable outside DAG code. Sources: airflow-core/src/airflow/ui/src/pages/Variables/index.tsx

The documentation architecture script shows how Airflow's package documentation is published from the repository into the live documentation site through release-manager and committer workflows, S3, CloudFront, and the airflow.apache.org web server. For this page, that context explains why users should read the official Variables, XComs, and Params pages for task-oriented examples while using the source mapping here to understand API and implementation boundaries. Sources: docs/images/documentation_architecture.py

Next Steps

When implementing a DAG, start by naming the runtime values it needs and deciding whether each is global configuration, run input, or task output. Then use Variables only for the first category, Params for the second, and XComs for the third. If you need to automate Variable management, use the public /variables API contract and preserve key immutability in client code. For adjacent concepts, read the pages on DAGs, Tasks and Operators, Connections, Secrets Backends and Masking, and the REST API and OpenAPI Clients.