Apache Airflow customization

DeployOpen builds custom Airflow code (operators, hooks, sensors, plugins and provider packages) with tests, packaging and authoring standards so it keeps working through Airflow 3 minor and patch upgrades. This page explains the scope, cost drivers and what to provide before you choose between your team and a partner.

On this page

What Airflow customization covers and when teams need it

Airflow customization means writing code that extends Airflow itself rather than only writing DAGs. The common components are operators, hooks, sensors, plugins, provider packages and shared DAG libraries. Operators define a unit of work, hooks wrap connections to external systems, sensors wait for a condition, plugins add views or macros to the installation, and provider packages bundle these pieces for distribution. Teams usually need this work for three reasons: the same connector logic is copied across many DAGs, an internal system has no existing provider, or several teams need one set of conventions for naming, retries, alerting and tagging.

Airflow 3 changes how this code must be written, so existing custom code should be reviewed before any upgrade. Task code can no longer open Airflow database sessions or import models directly. It must use the Task SDK and the REST API instead. Internal imports that worked in Airflow 2 may also break, because some module paths were moved or removed. The upgrade guide recommends checking DAG code with the Ruff AIR301 and AIR302 rules. Teams should run those checks against their custom libraries as well as their DAG folders, and confirm which internal calls their operators make against the metadata database.

In-house or partner is mostly a question of who will maintain the code after the first release. Teams with strong Python packaging skills and experience with Airflow internals can often build a small hook or operator themselves. A shared library used by many teams, a documented standards baseline and an automated test and packaging pipeline are harder to keep alive when one developer leaves. Many organizations bring in a partner for that foundation, then keep ownership of the business logic in-house. Ask any partner to show how the code is tested against the Airflow version you run and how the package is versioned and released.

What the work includes and what you receive

Customization work follows a fixed sequence: inventory what exists, decide how each piece should be packaged, build and test it, then hand it over with the material your team needs to maintain it through Airflow upgrades.

Discovery and inventory

We catalog existing DAG code, custom operators, hooks, sensors and plugins, and note which Airflow APIs and imports each one depends on. This shows which components can move unchanged to Airflow 3 and which need rework, such as code that uses database sessions or models directly, which Airflow 3 no longer allows in task code.

Component design decisions

For each piece of logic we choose between an operator, hook, sensor, plugin or provider package. Hooks hold connection logic, operators wrap a single unit of work, sensors wait on external state, and plugins or provider packages suit code shared across teams. Each choice is written down with its reason so future maintainers can see why it exists.

Implementation and test suite

We build the components with unit tests for logic and integration tests against the systems they connect to, run in a test environment that matches your target Airflow version. Test results are the evidence that custom code still works after a patch or minor upgrade, so you should confirm which external systems can be reached from your CI runners.

DAG authoring standards and templates

We define naming, folder layout, task ID conventions, retry and alerting defaults, and secrets handling as a written authoring guide, backed by a template repository new DAGs can start from. Linting with Ruff, including the AIR301 and AIR302 rules that Airflow's upgrade guide recommends, runs as part of the standard so non-compliant code is caught before review.

Packaging and versioned release

Custom components are packaged with versioned metadata and published to the private index or artifact store you operate. Each release records the Airflow version it targets, so teams can pin a package version against a known Airflow release. Confirm which index tool and access controls your organization already uses before the packaging plan is fixed.

Handover and upgrade checklist

Handover covers the source repository, package artifacts, test suite, CI pipeline definition, authoring guide and an upgrade checklist tied to the Airflow version in use. Your team receives a walkthrough of how to run the tests and cut a release, and the checklist lists which custom components to re-test before each Airflow upgrade.

What drives cost and duration

Each driver below is an input to a written quote rather than a fixed price, and the table shows why it moves effort and how to keep it contained.

DriverWhy it mattersHow to keep it down
Custom components and external systemsEach operator, hook, sensor or plugin needs its own design, tests and upkeep, and each external system adds credentials, network paths and failure modes to verify.Reuse existing provider packages where they fit, limit the first release to systems that run production DAGs, and defer low-value connectors.
Teams and DAGs depending on shared codeA change to a shared hook or base class can break many DAGs at once, so the more teams depend on it, the more regression work and coordination each release needs.Put shared code behind a versioned package with a stated owner, and migrate consumers in waves instead of changing the shared code in place.
Need to run on Airflow 2 during transitionCode that must work on both Airflow 2 and Airflow 3 requires compatibility layers and dual test matrices, which add design and test work until the Airflow 2 estate is retired.Set a retirement date for Airflow 2 early. Airflow 2 reached end of life on April 22, 2026, according to the Airflow version support table, so confirm whether any Airflow 2 runtime is still in use.
Executors and deployment environmentsPackages must install and behave the same on LocalExecutor, CeleryExecutor and KubernetesExecutor, and in each environment (local, Celery workers, Kubernetes images). Each combination adds packaging and smoke-test steps.Confirm which executors are in scope for the first release. Build one image or wheel pipeline that all environments consume, and document any executor-specific limits.
Compliance and code review requirementsRegulated teams often require documented review, change approval, dependency scanning and evidence of testing before custom code reaches production, which adds process time and artifacts.Agree the review gates and evidence format in the scope. Use the same pull request and CI checks for every package so evidence is produced by default.
Python versions the packages must supportAirflow 3.3.2 lists Python 3.10 to 3.14 as prerequisites. Each supported Python version adds a build, a test run and a possible dependency conflict to maintain.Choose the smallest Python range your runtime images use, and confirm it with the platform team before the build starts.
Depth of testing against real external systemsUnit tests with mocks are quick, but proving a hook works against a real database, API or message bus needs test environments, test data and secrets handling, which takes the most time in most builds.Use a defined set of integration tests against sandbox versions of each external system, and keep the rest at unit level. Confirm sandbox availability with the system owners early.

Project phases and outputs

The sequence moves custom Airflow code from an inventory of what exists to a tested, packaged and supported set of components that your team can run after handover.

  1. Inventory existing DAGs and custom code

    We list the DAGs, custom operators, hooks, sensors, plugins and connections in use, note which Airflow APIs and imports each one relies on, and flag code that reaches into the metadata database or uses removed features. The output is a written inventory with a recommended treatment for each item, reviewed with your data platform owners before design begins.

  2. Design interfaces against public extension points

    For each need, we choose the Airflow extension point that fits, such as an operator, hook, sensor, plugin or provider package, and confirm that it uses the public APIs for your target release. The output is an interface design document that names each component, its inputs and outputs, its dependencies and the Airflow version it targets.

  3. Build and test components

    We implement the components against the agreed design and write unit tests for their logic, plus integration tests that run them against a local Airflow environment. DAG code is checked with the Ruff rules for Airflow 3 before review. The output is source code in your repository, with a test suite that passes and a short note on any open issues.

  4. Package and wire up CI

    We package the components as an installable Python distribution or provider package with pinned dependencies, and add a pipeline that runs linting, tests and package builds on every change. The output is a versioned package, a CI configuration in your version control system, and build instructions your team can follow without us.

  5. Pilot in a non-production environment

    We install the package in a non-production Airflow environment that matches your production metadata database, executor and DAG delivery method as closely as the agreed scope allows. We run selected DAGs end to end and compare results with the current behavior. The output is a pilot report listing test results, defects found and fixes applied, with your sign-off before release.

  6. Hand over and agree support options

    We deliver the source, package, CI configuration, coding standards, runbooks for installing and upgrading the components, and a list of the Airflow versions each one supports. We then walk your engineers through operation and agree on any ongoing support, which is set out separately in the written scope. The output is a handover pack and a recorded session that your team has accepted.

What teams keep in-house and what they outsource

The table lists the parts of an Airflow customization project that teams usually keep, the parts they often outsource, and the skills each part requires, so the in-house owner can maintain the package after handover.

Work areaUsually kept in-houseUsually outsourcedSkills required
Business logicRules for how pipelines transform, validate and route data, decided by the people who own the data productsEncoding those rules as small, tested helpers that the DAGs callDomain knowledge, Python, unit testing with pytest; the owner must be able to change rules without a partner
Source system knowledgeSchemas, API quirks, rate limits, data-quality expectations and who to call when a source changesWrapping the source in a hook with connection handling and retriesFamiliarity with the external system, Airflow hook conventions, secrets handling through Airflow connections
DAG ownershipChoosing schedules, dependencies, ownership tags and which team is paged on failureAuthoring templates and a starter DAG that show the approved patternAirflow 3 concepts such as the Task SDK, TaskGroups and asset-aware scheduling; keep the DAG files in the client's repository
Extension pointsDeciding which operators, sensors or plugins the organization needs over the next several yearsDesigning the custom operators, hooks, sensors and plugin entry points so they fit Airflow's provider modelAirflow internals, provider package structure, Python packaging with pyproject.toml, versioning of public interfaces
Test and packaging pipelineOwning the CI configuration, release tags and where built packages are publishedSetting up linting, unit and integration tests against a local Airflow, and building installable wheelsCI tooling such as GitLab CI or GitHub Actions, Python packaging, Docker for test environments
Authoring standardsApproving the standards and enforcing them in reviewWriting the DAG and code conventions, including naming, error handling and Ruff rule configurationPython style tooling such as Ruff, knowledge of Airflow 3 import paths and the Task SDK
Airflow 3 compliance checksDeciding which findings must be fixed before an upgrade and who signs off on the upgrade dateFirst pass across the custom code using Ruff AIR301 and AIR302 rules and a list of removed featuresWorking knowledge of the Airflow 3 upgrade guide, removed direct database access and SubDAG replacements
Final review of merge requestsReviewing changes to business logic and DAGs before merge, with a named approver for each repositoryHandover review of the packaged code, documentation and runbook, so the internal team can judge future changesCode review in the client's own tooling, familiarity with the package's public interface and release process

What usually goes wrong and how to prevent it

Most Airflow customization problems come from code that depends on private internals, unchecked versions, or missing ownership. Each risk below pairs with a prevention step you can put into code review, CI and handover.

Internals and undocumented hooks

Custom code that imports Airflow internals, database models or undocumented plugin hooks breaks when Airflow changes them. In Airflow 3, task code cannot use database sessions or models directly and must use the REST API or Task SDK. Prevention: limit custom code to documented extension points and review every Airflow import during code review.

Loose or tight version pins

Unbounded provider ranges pull in changes that can break DAGs on the next image build, while exact pins can block security fixes. Test your constraints against the Airflow 3.3.2 prerequisites and your target Python version. Run a version matrix across the Airflow and provider releases you support in CI.

Packages shipped without scheduler tests

Unit tests that call an operator's Python function alone miss scheduling, serialization and retry behavior. Run each custom operator, hook and sensor inside a real Airflow 3 scheduler or development environment in CI before packaging. Test the built provider package as well as the source tree, and record the Airflow and Python versions each run used.

DAG code failing Ruff AIR checks

The Airflow 3 upgrade guide recommends checking DAG code with the Ruff AIR301 and AIR302 rules. Add these rules to a CI gate that blocks merges, and apply them to custom operators and shared DAG libraries as well. Keep a written exception list with a named owner and an expiry date for every finding you defer.

Secrets hard-coded into hooks

A hook that embeds a password, token or API key in code or a DAG file leaks it into version control and task logs. Resolve connection IDs through the secrets backend you configure so hooks read credentials only at runtime. Scan the repository for credential patterns in CI, and rotate any value that has already been committed.

No owner after handover

Custom code written during an implementation or by an engineer who has since left often has no named maintainer when the next Airflow release arrives. Assign an owner to each operator, hook and provider package. Document the test commands, supported Airflow versions and upgrade steps in the repository, and confirm who approves changes to shared code.

How the work differs by starting point

A new Airflow 3 deployment with a small DAG estate gives the most freedom in design, because no legacy code constrains the custom layer. The work is mostly about setting conventions before the library grows.

  • Scope: Define a small set of custom operators, hooks, or sensors only where existing providers do not cover a real need, and keep plugins to a minimum.
  • Testing: Set up DAG import tests and unit tests for custom hooks from day one, and run them in CI against the same Airflow version used in production.
  • Packaging: Start with a single internal package installed into the image, with a version number and changelog so later changes are traceable.
  • Compatibility: Confirm the Python and metadata database versions listed in the Airflow 3.3.2 prerequisites before pinning the image.
  • Authoring: Write DAG standards early, including use of the Task SDK in place of direct database access in task code.

What you need to provide

Customization work moves quickly only when the client has named the people and access it depends on before the build starts. Start by appointing a technical owner who can make decisions about shared code, and a reviewer who will approve merge requests. Without a named reviewer, custom operators, hooks and provider packages tend to wait in review queues, and the schedule slips in small steps that add up.

Next, provide read access to the existing DAG repositories and the Airflow configuration, with secrets excluded. Engineers need to see which custom code already exists, how connections are defined and which Airflow and Python versions each environment runs. Ask for the exact Airflow version and Python version in development, test and production. Custom code is tested against those versions, so a mismatch found late usually means rework in packaging and test fixtures.

Provide a list of every external system the custom code will call, along with sandbox or test accounts for each one. Missing access to a test system is the most common reason a schedule moves, because operators and sensors cannot be verified against a system that is not reachable. Confirm which systems have test instances, who owns the account requests, and how long your own approval process takes. Treat these as readiness items, not follow-up tasks.

Finally, decide three things in writing: the package index or artifact store where releases will be published, the secrets backend that custom hooks will read from, and the naming standards for DAGs, tasks, connections and packages. Also document the release and change process for shared code, including who approves a release and how upgrades of Airflow providers are scheduled. These decisions shape how custom code is packaged and how it survives the next upgrade.

Questions buyers ask before hiring help

What does Apache Airflow customization cost, and do you publish prices?

Cost follows the written scope, and DeployOpen does not publish a price list. The main drivers are the number of operators, hooks, sensors, plugins and provider packages in scope, how complex the external systems are, whether the work includes tests and packaging, and how much existing DAG code needs review or refactoring. Ask each quote to separate one-time build work from recurring items such as upgrade support, provider package updates and test maintenance. Also confirm the Airflow version the scope targets, since Airflow 3 changes how task code accesses metadata and which imports it may use.

How long does a custom Airflow operator or plugin project take?

Duration depends on the drivers in the scope, and the agreed timeline is fixed in the written scope before work starts. The main variables are the number of components, the depth of integration with source and target systems, the test coverage your team expects, and whether custom code must move to Airflow 3 at the same time. A small operator with clear inputs and outputs takes far less time than a provider package that must support several environments and release cycles. Ask for milestones tied to deliverables so progress can be checked against the plan.

Can our own engineers build custom Airflow code without outside help?

Yes, for small, well-understood extensions such as a single hook or sensor that wraps an API your team already knows. Those projects need Python skills, a working test suite and a clear owner for upgrades. Outside review is most useful in three areas: the boundaries of provider packages, the packaging and versioning approach, and the upgrade path across Airflow 2 and 3, where the upgrade guide changes how task code reaches the database and which imports are allowed. A second review of those areas usually prevents expensive rework after go-live.

What do you need from our team before a customization project starts?

Name a technical owner, and provide read access to the existing DAG repository, the Airflow version in use, and the external systems the custom code will call. Share the authentication model for those systems, the target environments, and any internal coding or review standards. Your team also needs to confirm who approves changes, who runs production deployments and who maintains the code after handover. A non-production Airflow environment is needed for testing. Confirm each item in the written scope so that delays caused by missing access are visible early.

How does custom Airflow code survive upgrades without breaking?

Custom code survives upgrades when it is tested against each Airflow and Python combination you plan to run, and when dependencies are pinned. The approach uses a test matrix covering the Airflow versions, Python versions and database backends in scope, version pins for Airflow and provider packages, and Ruff AIR checks, including the AIR301 and AIR302 rules that the Airflow 3 upgrade guide recommends. An upgrade checklist records each step, from moving to the latest 2.x release first to running the DAG processor and API server as separate components. Run the matrix on every release candidate and before each upgrade.

Does DeployOpen issue compliance certifications for our Airflow code?

No. DeployOpen does not issue audit reports, attestations or certifications. It prepares the evidence an independent auditor or certification body needs, such as documented change control, test results, dependency records, access reviews of the code repository and the upgrade checklist. Your assessor decides what is sufficient for your framework. Ask the assessor early which artifacts they expect for custom code, because that evidence is easier to plan in advance than to reconstruct later.

How DeployOpen scopes, delivers and supports Airflow customization

DeployOpen plans, builds, tests, documents and supports custom Airflow code inside infrastructure you control, with the written scope fixed before work starts. The method is built so custom operators, hooks, sensors, plugins and provider packages can be carried across Airflow upgrades.

How we scope

  • We inventory existing DAGs, plugins and custom providers, and list which ones depend on Airflow database sessions or models.
  • The written scope names each custom component, its target Airflow 3 interface and the environments it must run in.
  • Scope records which Python, database and Kubernetes versions the custom code must support, checked against the Airflow prerequisites.

How we build

  • Custom operators, hooks and sensors are built against the Task SDK and REST API rather than direct database access.
  • Packaging follows a documented build process, so provider packages and plugins install reproducibly into your images.
  • Each component ships with unit tests, DAG import checks and Ruff AIR301 and AIR302 rule runs wired into your pipeline.

How we hand over

  • Handover includes DAG authoring standards, a code ownership map and a runbook for building and promoting custom packages.
  • Your team receives the test suite, packaging scripts and version pinning records needed to repeat the build without us.
  • We agree in writing what documentation, training sessions and acceptance checks close the engagement.

How we support

  • Ongoing support covers reviewing custom code when Airflow minor releases and provider packages change, available as a retainer.
  • Upgrade work is planned against the Airflow version life cycle, so custom code is tested before a supported release reaches end of life.
  • Confirm with us during scoping which support hours, response targets and upgrade reviews a retainer includes, since these are set per agreement.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.