Installing Apache Airflow from PyPI with constraints: when pip is the right route
A platform team that must run Apache Airflow inside infrastructure it controls, but has no container image pipeline and no Kubernetes deployment to hang it on, can install Airflow directly into a Python environment with pip. The PyPI route gives that team an environment built from pinned versions of Airflow, its providers and their dependencies, installed on a virtual machine or a build host the team already runs. It suits single-team deployments on VMs, teams whose Python tooling is already governed by an internal package mirror, and teams that want to see every dependency before it reaches production. It is a weaker fit when the same release must run identically across many hosts or clusters, because the environment is then rebuilt on each host rather than shipped as one artifact.
The reason this route works at all is the constraint file. A plain pip install apache-airflow resolves dependencies at the moment it runs, so two installs a month apart can differ, and the result may not be a usable Airflow. Airflow publishes a constraints file for each release and Python version, and passing it to pip pins every transitive dependency to a tested combination. Before choosing this route, confirm that your Python version appears in the constraints set for the Airflow release you plan to run, using the prerequisites for that release, and confirm which Python interpreter your hosts will actually use.
Choosing pip also means owning the artifacts that a container build would otherwise freeze. Decide where the constraints file is fetched from and whether it is copied to an internal server, because a build that depends on a public file path breaks in a restricted network. Decide who approves changes to the pinned set and how a new Airflow patch release enters the environment. Ask any partner quoting this work to name the constraints source, the mirror or repository that holds the packages, and the rebuild procedure for each Airflow patch, since those three decisions determine how repeatable the install stays after go-live.
Which pip install pattern fits your environment
This table compares three ways to install Airflow and its providers with pip: the published constraint URL, a constraints file you freeze and host internally, and a separate provider install pinned to the Airflow version. Read each row for the main use case, who maintains the constraint input, and the trade-off you accept. For most teams with internet access, the published constraint URL is the starting point, and an internal copy is worth the upkeep only when you need repeatable or offline installs.
| Pattern | Main use case | Who maintains the constraint input | Main trade-off |
|---|---|---|---|
| Published constraint URL per Airflow and Python version | Standard installs on hosts with outbound access to GitHub, such as a VM or a build pipeline | The Airflow project publishes the file for each release and Python version | Installs depend on the public file being reachable at build time, and you must match the URL to your exact Python version |
| Internal frozen and hosted constraints file | Air-gapped or tightly controlled networks, and builds that must produce identical results over time | Your platform team copies the public file, pins any extra packages, and hosts the result on an internal server | You own the refresh cycle: each Airflow patch or provider change needs a new copy, tested and approved before rollout |
| Providers installed in a separate step pinned to the Airflow version | Adding provider packages such as warehouse or cloud connectors without destabilizing the core install | You choose which providers to add, and the pin keeps them aligned with the Airflow version | Constraints apply only to the pip command they are used with, so provider installs must reuse the same constraint source to avoid conflicts |
| Combined: internal constraints plus a separate provider step | Regulated environments that need both a reviewed dependency set and a predictable provider upgrade path | Shared between the platform team (hosted file) and the owners of each provider | Highest upkeep, but the clearest audit trail for which versions ran in production |
How to install Airflow 3 from PyPI with constraints, step by step
This sequence takes a clean host from an unconfigured Python environment to a frozen, internally hosted constraint set that the team can reuse for every later install. Each step ends with a check so the next step only starts once the previous one has passed.
Confirm the Python and database prerequisites
The platform engineer checks that the host runs a Python version from 3.10 to 3.14, the range listed for Airflow 3.3.2. In the same step, confirm that the metadata database will be PostgreSQL 14 to 18 or MySQL 8.0, 8.4 or an Innovation release, and that MariaDB and SQLite are excluded for this purpose. Do this before any Airflow component starts, because the database choice determines how the scheduler, API server and workers connect. Done means the Python version prints inside the range and the database version and connection details are written down for the configuration step.
Create an isolated virtual environment
Create a dedicated virtual environment for Airflow so its dependencies do not mix with system Python packages or other applications on the host. Activate it in every shell that will run pip or Airflow commands, and record the interpreter path that the environment uses. Done means the interpreter inside the environment reports the same Python minor version checked in the previous step, and the environment's pip is the one you will use for all installs.
Install Airflow with the release and Python constraint file
Install apache-airflow using the constraint URL that matches the Airflow release and your Python version, from the constraints location the Airflow PyPI guide describes. The constraint file pins the transitive dependencies that the release was tested with, and it applies only to the pip command it is passed to, so keep it on every install you run in this environment. Done means pip completes without resolver conflicts and the
airflowcommand is available inside the environment.Install each provider in its own pinned step
Install each provider package your DAGs need in a separate pip command, pinned to the Airflow version and passed the same constraint file. Keep the provider list short and written down, because each provider adds dependencies and each one can bring a system library requirement that the OS packages step must cover. Done means every provider installs cleanly and
pip checkreports no broken requirements.Install required OS packages for providers
Some providers depend on system libraries, such as client libraries for database drivers or cryptography toolchains. Install only the OS packages that the failed or documented provider installs require, through your platform's package manager and approved mirror. Confirm each provider's documentation for its native dependencies, since the provider list determines this set. Done means the provider imports succeed from the Python shell inside the environment, for example by importing each provider module.
Run the version and configuration check
Run
airflow versioninside the environment and confirm it reports the Airflow 3 release you pinned. Then run the configuration check with the metadata database connection set to the PostgreSQL or MySQL instance from step one, and run the database migration command against that database, not SQLite. Done means the version matches the constraint file, the migration completes, and the database contains the Airflow schema tables.Freeze and host the final constraint set
Export the installed package set with
pip freezeand compare it with the upstream constraint file to confirm that every pinned version matches. Save the frozen list as your team's own constraints file and publish it to an internal server or artifact store that your build and air-gapped installs can reach. Done means the internal file installs the same package set into a fresh environment, and the file is stored under version control with the Airflow release and Python version in its name.
Installing with constraints in connected, mirrored and air-gapped networks
A connected build installs Airflow and its providers directly from the public package index, using the constraints file published for the exact Airflow release and Python version in use. Pip resolves against the public constraints URL on each run, so the team does not host any artifacts itself, but it also has no control over when a build picks up a new transitive dependency. The constraints apply only to the pip command they are used with, so the provider install must repeat the same constraints reference.
- What must be available: outbound HTTPS access to the public package index and to the constraints location for the target Airflow version and Python version.
- Who updates it on each patch: the platform team changes the Airflow and provider version pins in its build definition when it adopts a patch release.
- What to verify before promotion: that the constraints URL resolves for the Python version in the build image, and that
airflow versionand the provider list match the pinned values. - Main risk: a constraints file that changes upstream is not the same artifact you tested. Record the resolved package list from each build.
- Scope note: confirm with your security team whether outbound package access is permitted from build runners at all.
Before promoting, compare the resolved package list with the previous build and confirm the Airflow import and a DAG parse succeed.
A mirrored build keeps the same pinned versions but resolves packages from an internal package index and reads a constraints file hosted on an internal server. This is the usual model for regulated networks that allow internal package repositories but block direct internet access from build hosts. The team that owns the mirror must sync the Airflow packages, the chosen provider packages, and their dependencies, and must publish a constraints file that matches the upstream one for the release in use. Hosting your own frozen constraints file is a supported approach described in the PyPI installation guide.
- What must be available: an internal package index containing Airflow, each selected provider, and all transitive dependencies for every supported Python version, plus the constraints file hosted internally.
- Who updates it on each patch: the mirror or artifact team syncs the new release, and the platform team publishes an updated internal constraints file and changes the pin.
- What to verify before promotion: that the internal constraints file matches the upstream file for the same release, and that a clean install from the mirror produces the expected package list.
- Main risk: a mirror that is partially synced installs successfully on one day and fails on another. Confirm sync completeness, not only the presence of the top-level packages.
- What to ask your team or partner: who owns mirror sync, how often it runs, and how removed or yanked packages are handled.
Before promotion, run the install on a clean runner with network access limited to the mirror, then confirm that the resolved versions match the internal constraints file.
A fully disconnected network has no route to public package indexes or constraints locations. Every wheel, source distribution, system package and constraints file must be staged in advance, and the build must be reproducible from that staged set alone. The staging process is a controlled transfer, so it usually involves a review step and a record of what entered the enclave. Plan the bundle around the exact Airflow release, every provider and Python version your fleet runs, and the OS packages some providers need, since those cannot come from pip.
- What must be available: a versioned bundle with Airflow, all selected providers, dependencies, the constraints file for each Python version, and any OS packages required by installed providers.
- Who updates it on each patch: a bundle owner in the staging zone downloads and reviews the patch release, then the platform team moves the signed bundle across the boundary through your approved transfer process.
- What to verify before promotion: that the install completes with networking disabled, that checksums match the staged manifest, and that a DAG parse and a scheduler start succeed in the enclave.
- Main risk: a missing transitive dependency surfaces only in production. Test the install in a disconnected staging environment first.
- What to confirm: the transfer process, retention of old bundles for rollback, and which providers your industry or auditors require you to keep in the bundle.
Keep the previous bundle available until the new build has run successfully in the enclave for a period your change process defines.
OS packages and prerequisites some providers need before pip runs
A constraints file pins Python packages, but it does not install compilers, headers, database client libraries or certificates that some providers need at build or run time. These cards list the host-level prerequisites to check before pip runs, and the exact list depends on which providers you install.
Python interpreter and development headers
Airflow's constraint file is generated for a specific Python version, so the interpreter on your host must match the file name you install against. The supported range for Airflow 3.3.2 is Python 3.10 to 3.14. Some providers ship compiled extensions that need the matching Python development headers to build from source when no prebuilt wheel exists. Confirm the interpreter version against the prerequisites page and the headers package for your OS image.
Build tools for compiled dependencies
Some provider dependencies include C extensions without a wheel for your platform, so pip compiles them with a compiler toolchain and build utilities on the host. A build that works on a developer laptop may fail on a hardened base image that omits these tools. Record which packages were compiled during the install, because that list tells you whether the build toolchain must stay in the image or can be removed afterward.
Client libraries for the metadata database
The metadata database connection needs a driver that matches your chosen backend, such as a PostgreSQL client library for a PostgreSQL metadata database or a MySQL client library for MySQL. Some drivers need system libraries at build time. MariaDB and SQLite are not supported for production metadata, so do not install a client for them as a shortcut. Confirm the driver and its system dependencies against the database extra or provider you install.
System certificates for internal endpoints
Package indexes, artifact mirrors and internal services may use certificates issued by your private certificate authority. If the host trust store does not include that authority, pip and provider code that calls internal endpoints will fail during install or at runtime. Add the CA bundle to the system store before the first install and confirm that pip picks it up. Ask your security team which internal endpoints each provider will contact.
Time zone, locale and clock settings
Scheduling depends on correct time zones and a synchronized clock, because cron expressions, data intervals and logs all rely on consistent timestamps. Locale settings can also affect how some Python libraries encode text during install and execution. Set the host time zone and enable time synchronization before you install, and confirm that the locale is UTF-8 on the image. Check each provider's documentation for any locale or time zone assumptions it makes.
Memory for installation and running Airflow
Installing and running Airflow requires enough memory for the scheduler, API server, DAG processor and workers, so size the host before the install. The prerequisites recommend at least 4 GB of RAM. Compiling larger provider dependencies can need more headroom during the build than at steady state. Measure memory during a trial install on the target host class, and do not treat the minimum as a sizing decision for production.
How long a PyPI install with constraints takes and what it asks of your team
What actually drives the effort of a PyPI install with constraints?
The effort follows the size of the dependency set, not the base install. The main drivers are the number of providers you need, whether pip can reach public PyPI or must pull from an internal mirror, any air-gap rules that block downloads at install time, your choice of Python version from the range Airflow 3.3.2 supports (Python 3.10 to 3.14), and the database driver setup for PostgreSQL or MySQL. Each provider adds packages, and some need OS libraries that must be installed before pip can build them. Ask your partner to list every provider and system package in the written scope before work starts.
Can a capable platform engineer do the PyPI install alone?
Yes, for a single environment with public package access, a supported Python version and one metadata database, a platform engineer who knows Python packaging can follow the official install steps. The harder part is repeatability: freezing your own constraints file, hosting it where every environment can read it, and proving that a patch upgrade changes only what you expect. Teams that run several environments, need an internal mirror, or must satisfy change control often find it more predictable to have a partner set up the pattern once and hand over a runbook.
What does the install need from our team?
Plan for access and decisions, not just time. You will need Python and OS access on the target hosts with permission to install system packages, network paths to the Airflow constraints location or your internal mirror, endpoints and credentials for the PostgreSQL or MySQL metadata database, and a version-controlled place to host the frozen constraints file. You will also need a named approver for Airflow upgrades, because each patch changes the pinned set and may need a change record. Confirm these items with your security and network teams before the kickoff.
What recurs each time Airflow gets a patch release?
The initial install is one-time work. Each Airflow patch release means rebuilding the constraints for the new version, testing the environment against the new pinned set, updating any provider you have pinned, and reviewing the release notes for breaking changes. Airflow 2 is already in limited maintenance and reached end of life on April 22, 2026, so anyone still on Airflow 2 should plan the move instead of only patching. Ask whether the scope includes repeat patch cycles or only the first install, and what the retainer covers if you choose ongoing support.
Does the scope include security patching of the installed packages?
Confirm this explicitly, because it changes the effort every quarter. Airflow's support policy gives limited-maintenance versions security and critical bug fixes only, and end-of-life versions get no fixes at all. A frozen constraints file keeps installs reproducible, but it does not find new vulnerabilities by itself. Ask whether the partner will scan the resulting environment, rebuild on each security fix, and record which constraints changed, so your evidence trail stays current.
What should a written quote for this work include?
A quote should follow from a written scope, and it should list the Airflow version and Python version, each provider and system package, the database and driver, the number of environments, whether an internal mirror or hosted constraints file is in scope, and the handover items such as runbooks and the constraints repository. Ask which items are one-time and which are recurring, what a patch cycle costs in effort, what happens if a provider fails to resolve, and who is responsible for the change record. DeployOpen does not publish prices, so request a quote against that scope.
How do we confirm the timeline before we commit?
No general duration can be quoted here because the work depends on your environment. Ask for a schedule tied to milestones: environment access, a first successful install from constraints, a tested provider update, and handover. Confirm which of your approvals sit on the critical path, such as mirror access or change board dates. A partner that can explain which of these steps are blocked by your side can give you a realistic plan without guessing.
Securing the install: constraint sources, package integrity and the frozen file
A constraints file decides which versions of Airflow and its providers reach production, so it becomes part of your change management and recovery record. The cards below cover where the file comes from, who can change it, what the build can reach, and how you prove later what ran.
Trust the constraint source
Constraint files are published by the Airflow project in its GitHub repository, but your build should not fetch them live from the internet on every run. Decide whether you trust the upstream file for a given release, then copy the reviewed file into your own controlled location. Record the source URL, the Airflow version and the Python version in your change ticket so an auditor can match the file to the release.
Control who changes the hosted file
A frozen constraints file is a list of pinned versions, so a silent edit changes what every future build installs. Limit write access to the repository or server that holds it, require a reviewed merge or approval for each change, and keep the commit history. Ask who may approve a bump and whether that person is separate from the one who requests it.
Limit which package indexes the build reaches
A build that can reach several package indexes may pull a package from a source you did not approve, even when the versions are pinned. Configure the build to use only your internal mirror or approved index, and disable fallback to public indexes in production pipelines. Confirm which index each provider package resolves from before you accept a build.
Record the exact installed versions
Export the full resolved package list from the built environment, such as the output of pip freeze, and store it with the build artifact and the release record. This gives you evidence of what ran on a given date and a precise baseline for rollback. Compare the recorded list with the constraints file to catch any package that was added outside the pinned set.
Restrict access to the internal constraints server
The internal host that serves your frozen file is part of the supply chain for every Airflow environment. Grant read access only to build systems and the people who maintain them, enforce TLS on the connection, and log downloads. Confirm that a compromised workstation cannot upload a replacement file to that location.
Stage provider updates before production
Provider packages move on their own cadence, so a routine rebuild can change a connection or operator behavior that your DAGs depend on. Build the new constraints file in a staging environment, run your DAG test suite against it, and promote the same file to production only after it passes. Keep the previous file available so a rollback reinstalls known versions.
Avoid installing as a privileged user
Installing packages as root or with administrator rights on a shared host lets any installed package change system files and other services. Create a dedicated service account, install Airflow into a virtual environment owned by that account, and keep the scheduler and workers running under unprivileged users. Confirm this in your host hardening baseline, because it also limits the damage from a malicious or faulty provider package.
How DeployOpen scopes and delivers a PyPI-based Airflow install
DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside your own infrastructure, and that includes a pip-based Airflow install pinned to constraint files. Engagements are fixed-scope, so the scope, deliverables and timeline are agreed in writing before any installation work starts.
How we scope
- We confirm the Airflow release line, Python version and provider list your team needs before any install begins.
- The written scope names the constraint file source, whether it is hosted upstream or on your internal server.
- We record which database, OS packages and provider updates are in and out of the agreed deliverables.
How we build
- We build the virtual environment or image from a pinned constraints file and install providers in a separate, version-matched step.
- We freeze a constraints file for your own environment and check that the resolved package set installs cleanly.
- We test each Airflow component start-up and a sample DAG run against your chosen metadata database before handover.
How we hand over
- You receive install runbooks, the pinned constraint and requirements files, and a list of OS packages the providers need.
- We document how to repeat the install on a new host and how to move to the next patch release.
- Knowledge transfer sessions walk your platform team through the upgrade steps and the places where constraints must be refreshed.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer, scoped separately from the initial install.
- Retainer work can cover monitoring new Airflow patch releases and rebuilding your frozen constraints when you adopt them.
- Before any retainer starts, we confirm the support scope and which Airflow release lines your team will run.

