When Airflow UI plugins with React and FastAPI are worth building
Build an Airflow UI plugin when a platform team needs an internal view, an approval screen or an API endpoint inside Airflow 3 that the stock interface does not provide. Airflow 3 supports plugins that add both UI and API surface, so the question is less whether it can be done and more whether the extra screen or endpoint justifies owning code that must survive every upgrade. A plugin is well suited to read-mostly operational views, such as a status panel for a set of DAGs, or to a narrow endpoint that an internal tool calls. It is a poor place for business logic that belongs in a DAG, for data movement, or for anything that should live in a separate service with its own release cycle.
Plan for the plugin model Airflow 3 actually uses. Flask-AppBuilder views, menu items and blueprints must be converted to FastAPI apps or run through the FAB provider's compatibility layer, so any older plugin that adds Flask pages needs a decision before the upgrade, not after it. The React plugin system arrived in Airflow 3.1.0 alongside the AIP-68 work, which lets you add UI components to the web interface using React rather than server-rendered Flask templates. Before committing, confirm which Airflow version your environment will run, whether your existing plugins use Flask-AppBuilder, and which plugin keys (external_views, fastapi_apps, fastapi_root_middlewares) match each piece you intend to build.
Treat the build as a maintained interface, not a one-off script. Each plugin ties your code to Airflow internals that can change between minor releases, so ask who will own the plugin, how it will be tested against each new patch, and what happens if a feature you depend on moves in the Airflow 3 upgrade guide. If the answer is unclear, a simpler option such as a link to an existing external dashboard, or a script that calls the Airflow REST API, may serve the team with less upkeep.
Choosing between external views, React plugins, FastAPI apps and middlewares
External views add a menu entry or page to the Airflow UI that points to a page you host elsewhere, or embeds that page inside the UI. Use them when a team needs a link into an internal tool, a runbook, a dashboard or a status page from within Airflow, and the content does not need to read Airflow state through new code. The plugin registers the view under the external_views key, so the Airflow UI shows it as a navigation item without changing Airflow's own pages.
- Typical use: Linking operators to a monitoring dashboard, a data catalog entry or a change ticket for a DAG.
- Plugin key:
external_views. - Main risk: Embedding a third-party page can expose the signed-in user's Airflow session to content you do not control, so confirm the embedding policy and content security settings before enabling it.
- Upgrade exposure: Low, because the plugin depends on the registration interface rather than Airflow internals.
- Ownership: Confirm with the owning team who maintains the target page and what happens when that page moves.
Before approving an external view, check which pages it reaches, what data those pages receive from the browser, and who answers when the link breaks.
React plugins extend the Airflow 3 UI with custom components, which Airflow loads as part of its own frontend. The React plugin system arrived in Airflow 3.1 with AIP-68, and it lets a plugin render content inside defined extension points. Use this option when a team needs an operator-facing component such as a status panel or a custom page layout that must sit inside the Airflow interface. Because the component runs in the same browser context as the UI, it inherits the user's permissions and any defects in its code affect the whole UI.
- Typical use: Adding a DAG-specific status widget or a team-specific page inside the Airflow UI.
- Plugin key: Registered through the plugin system; confirm the exact key and registration method for your Airflow version in the plugin documentation.
- Main risk: Frontend code runs with the signed-in user's rights, and extension points can change between minor releases, so a component can break or silently stop rendering after an upgrade.
- Version dependency: Available from Airflow 3.1 onward, so older 3.x installations need a different approach.
- Build and release: Confirm the build chain, the frontend dependencies and the testing process you need to ship changes safely.
Confirm which React extension points the installed Airflow version exposes before designing any component, and pin the Airflow version your plugin is tested against.
FastAPI apps add new routes to the Airflow API server, so a plugin can expose endpoints that other systems or internal tools call. Airflow 3 replaces the Flask-based webserver with an API server, and FastAPI is the framework that Airflow now uses for plugin-provided HTTP routes. Use this option when an internal system needs a controlled endpoint that Airflow does not provide, such as a custom status endpoint for a release process. Each new route becomes part of the API surface you must secure and maintain.
- Typical use: Exposing an internal status or approval-support endpoint for a release tool.
- Plugin key:
fastapi_apps. - Main risk: A new route that skips authentication or authorization checks can expose Airflow data or actions, so every route needs an explicit access decision.
- Database access: Task code and plugins cannot use Airflow database sessions directly, so confirm which data sources the endpoint reads and how it reads them.
- Migration path: Flask AppBuilder blueprints from Airflow 2 must be converted to FastAPI apps or run through the FAB provider's compatibility layer.
Review each route against your access model, and confirm how your chosen auth manager authenticates requests to plugin routes before exposing any of them.
FastAPI root middlewares wrap every request that reaches the Airflow API server, so a middleware can inspect, modify or reject traffic before Airflow's own handlers see it. Use this option for cross-cutting concerns such as adding request headers, recording request metadata for audit, or enforcing a site-wide rule. Because the middleware runs on every request, a defect or slow code path affects the whole API, not a single route. Treat it as platform code that needs the same review and testing as Airflow itself.
- Typical use: Adding a standard request header, recording audit metadata or applying a network-level rule across the API.
- Plugin key:
fastapi_root_middlewares. - Main risk: A middleware that fails or adds latency degrades every API call, including those used by the UI and by workers, so test it under realistic load.
- Ordering: Confirm how middlewares stack and which one runs first when several plugins are installed.
- Security review: Involve your security team early, because middleware sits on the request path that authentication depends on.
Ask your team to document every middleware and its position in the stack, and check that it still runs correctly after each Airflow upgrade.
How to build and register a plugin step by step
This sequence takes a plugin from a version check to a working extension visible in the Airflow 3 UI and API docs. Each step ends with a check you can record, so load failures are caught in a non-production environment before the plugin reaches production images.
Confirm the target Airflow 3 version
Pick the Airflow 3 patch release you will run in production and check it against the prerequisites page: the supported Python interpreter, the metadata database (PostgreSQL or MySQL, not SQLite or MariaDB) and the Kubernetes version if you run on a cluster. For the 3.3.2 patch release, the prerequisites list Python 3.10 to 3.14 and PostgreSQL 14 to 18. If the plugin comes from Airflow 2, the upgrade guide requires Airflow 2.7 or later before the move. Done when the version, interpreter and database are written in your change record and match the prerequisites.
Write the plugin class and declare keys
The plugin developer subclasses Airflow's plugin base class and declares what the plugin provides using the preferred keys: external_views for links that open inside the UI, fastapi_apps for FastAPI sub-applications, and fastapi_root_middlewares for middleware on the root app. Plugin code should call the REST API for Airflow state instead of opening database sessions or importing Airflow models. Add React assets only if you target the React plugin system introduced in Airflow 3.1. Done when the module has no syntax errors and each declared key matches a component you intend to ship.
Test the plugin outside the scheduler
Run the tests in a virtual environment built with the same Python version and the constraints file for your pinned Airflow version. Import the module, instantiate the plugin, confirm the declared keys are present and send requests to the FastAPI routes with a test client. Scan the code for imports of Airflow database sessions or models and remove any you find. Done when the import and route tests pass in CI on the same Python version as the production image.
Package and install into the image
Build the plugin as a versioned Python package and install it into the container image that runs the API server, using the constraints file for the pinned Airflow version. The API server must load the plugin, so the package belongs in that image. If you deploy with the official Helm chart and Docker image, add the package in your image build and reference the new image tag in the values file. Done when inspecting the running image shows the package at the expected version and the constraints check passes without conflicts.
Restart the API server and check logs
Roll the API server so it imports the new package. In Airflow 3 the API server replaces the webserver, so restart it through your deployment tooling instead of the old webserver command. Read the startup logs for plugin import errors, missing dependencies or failed route registration. Then open the Airflow UI and the API docs and confirm the new external view and FastAPI routes appear. Done when the logs show no plugin load errors and both entries are visible.
Verify access and auth behavior
Sign in as users with different roles and confirm each plugin page and endpoint respects the same permissions as core Airflow. Check which auth manager your deployment uses, because Airflow 3 uses the Simple auth manager by default and allows only one, set by the auth_manager option. Call plugin endpoints without a token and confirm they are refused. Record each result against the role matrix. Done when the role tests pass and no plugin endpoint answers unauthenticated requests.
Record the pin for upgrade testing
Save the plugin version, the Airflow version, the Python version and the constraints file in your repository next to the image build. Before each Airflow patch or minor upgrade, rerun the test and load steps against the new image in staging. Keep the Ruff AIR301 and AIR302 checks in the same pipeline so breaking changes are flagged early. Done when a staging rebuild with the next Airflow version either passes the same checks or produces a documented list of changes to make.
Migrating Flask AppBuilder plugins to FastAPI or the FAB compatibility layer
Every Flask-AppBuilder plugin in your Airflow 2 estate needs an explicit decision before the upgrade: convert it to FastAPI or run it through the FAB provider's compatibility layer. Airflow 3 requires Flask-AppBuilder views, menu items and blueprints to be converted to FastAPI apps or run through that compatibility layer. The plugin keys to target are external_views, fastapi_apps and fastapi_root_middlewares. Decide per plugin, not per estate. A small internal page that only displays a status may move cleanly to a FastAPI app, while a plugin that depends on FAB security manager behavior or a large set of Flask views may be cheaper to keep on the compatibility layer for now. Record the owner, the routes it exposes, the roles that can reach it and the business reason for keeping it, because those answers drive the choice.
Plan for redesign, not just porting. In Airflow 3, task code can no longer use Airflow database sessions or models directly and must use the REST API or the Task SDK instead. Any plugin or helper that queried the metadata database from inside a task, or that imported models into DAG code, will break even if its UI renders correctly after conversion. Inventory those calls with the upgrade guide's checks before estimating work, because the data access layer often changes more than the view code. Also note that the FAB auth manager is delivered by the FAB provider, not by core Airflow, so a plugin that assumes FAB login and roles needs that provider installed and configured as a deliberate dependency.
Start from Airflow 2.7 or later, as the upgrade guide requires, and move to the latest 2.x release before crossing to Airflow 3. Then run the Ruff AIR301 and AIR302 rules across DAG code and plugin packages to surface removed or changed interfaces, and treat each finding as a line item in the migration backlog. Confirm the exact Airflow and provider versions that your chosen plugins support with their maintainers, and test every converted plugin on a staging environment that mirrors your production authentication setup. Ask any internal or vendor plugin team to state which Airflow version they target and how they handle future upgrades, since an unmaintained plugin is the most common reason an upgrade stalls.
Plugin options and when each fits
This table compares the four plugin routes available in Airflow 3 and a converted Flask-AppBuilder view, covering purpose, plugin key, what each touches and how exposed each is to upgrades. Read it by matching your extension goal to a row, then confirming the key and behavior against the Airflow version you run, since the React plugin system arrived in 3.1.
| Option | Plugin key and purpose | What it touches | Upgrade exposure and when to choose it |
|---|---|---|---|
| External views | external_views. Adds a link or page that opens an external web application from the Airflow UI. | The Airflow UI navigation and a separate web app you host. Airflow does not render the page. | Low coupling to Airflow internals. Choose it when the tool already exists elsewhere and users only need a launch point. Confirm the menu placement options in your version. |
| React plugin (AIP-68) | Introduced in Airflow 3.1 as the React plugin system. Adds UI components built with React into Airflow pages. | Airflow frontend components and their rendering. Confirm which UI extension points your version exposes. | Tied to the UI build and frontend contracts, so it needs retesting on each minor upgrade. Choose it for in-UI views that must look and behave like native Airflow pages. |
| FastAPI apps | fastapi_apps. Mounts a custom FastAPI application that serves your own API routes. | The Airflow API server process and its routes. Confirm which Airflow services your app may call. | Depends on the FastAPI and Airflow API surface you use. Choose it for custom endpoints that other tools or your own UI need to call. |
| FastAPI root middlewares | fastapi_root_middlewares. Wraps requests to the API server with middleware such as logging, headers or request checks. | Every request that passes through the API server, not a single page or route. | Highest blast radius because it affects all traffic. Choose it only for cross-cutting behavior such as request logging, and test ordering with other middlewares on each upgrade. |
| Converted FAB view | Flask-AppBuilder views, menu items and blueprints moved to FastAPI apps, or run through the FAB provider's compatibility layer. | Existing Flask-AppBuilder code and its menus. Confirm whether your plugin depends on the FAB provider. | Required work for any legacy FAB plugin under Airflow 3. Prefer converting to a FastAPI app or React plugin over relying on the compatibility layer, and confirm the provider version that supports it. |
Security risks in custom plugin code
A plugin that adds routes or views to the Airflow 3 UI and API runs with access the rest of your deployment depends on. The risks below connect because each one widens what a single piece of custom code can reach, read or change.
Plugin code runs in the API server
FastAPI apps and middlewares loaded through fastapi_apps and fastapi_root_middlewares execute inside the API server process. A bug or malicious change in plugin code can affect every request the API server handles, not only the plugin's own routes. Confirm which process hosts each plugin in your deployment and whether the API server can be isolated from other workloads.
Authorization on every new route
Each new route is only as protected as the check you write for it. Routes added by a plugin do not automatically inherit the access rules you configured for built-in endpoints. Confirm how your configured auth manager authenticates requests to plugin routes, and test that an unauthorized user receives a refusal for every method, not only for the page the UI shows.
Secrets in plugin configuration
Plugins often need API tokens, database passwords or endpoint credentials. Keeping them in plugin source, environment variables visible to every component, or the UI leaks them to anyone who can read the repository or the process environment. Ask where each secret is stored, which processes can read it, and whether a secrets backend or Kubernetes secret is used instead.
Dependency pinning and supply chain
Each Python package a plugin imports becomes part of the API server environment. Unpinned or transitive dependencies can change between builds and introduce vulnerable or incompatible code without a visible change in your repository. Pin versions with a lock file or constraints, scan the resulting image, and record which build is running in each environment.
Logging of plugin actions
Plugin routes that change state, such as triggering runs or writing configuration, need records that show who acted, what changed and when. Without them, an audit of a plugin-driven change depends on guesswork. Confirm that the plugin writes to the logs you forward to your central system and that those entries include the authenticated user identity.
Review gates before production
Plugins can change UI behavior and API surface on every deployment, so they need the same change control as DAG code. Require code review for plugin changes, a staging run against your auth configuration, and a documented rollback path. Ask who approves a plugin release and how that approval is recorded.
Keeping plugins working across Airflow 3 upgrades
Plugins must move with the platform, and the upgrade plan has to say so before the Airflow version changes. Pin the Airflow version your plugins are tested against, along with the provider and FastAPI versions they import, in the same version-controlled manifest that builds your Airflow image. Treat that pinned set as one unit: a patch release of Airflow can change the plugin surface, and a plugin that loads on the old image may fail on the new one. Keep the plugin on a tested Airflow version and move the pin deliberately, not as a side effect of rebuilding an image.
Before each upgrade, read the Airflow release notes for every version between your current pin and the target, and list anything that touches the UI, the REST API, plugin loading, the React plugin system or the FastAPI app lifecycle. Then run a regression suite against a staging deployment built from the target image. The suite should load each plugin, confirm that every external view and FastAPI route still renders and responds, check that the middlewares still wrap requests as intended, and verify that the plugin's own calls to the Airflow API still succeed. Record the results so the upgrade has evidence attached.
Support windows set the deadline. The Airflow support policy says limited-maintenance versions receive only security and critical bug fixes, and end-of-life versions receive none. Confirm the current status of your running version in the Airflow version life cycle table, and schedule plugin upgrades so that they finish before your version reaches end of life. A plugin that works today on an unsupported Airflow version is a liability, because you will need to patch the platform and the plugin together under pressure.
Limits to confirm before you commit to a plugin design
Plugin work sits on top of an interface that changed a lot between Airflow 2 and Airflow 3, so the design depends on what your installed release actually exposes. The four to six checks below connect the UI extension points, the execution model, authentication and the deployment method, and each one should be answered in writing before a build is scoped.
Which React extension points exist
Confirm which React plugin extension points are present in the exact 3.x release you will run, since the React plugin system was introduced in Airflow 3.1 and the set of places a plugin can attach may differ between later patch releases. Ask the vendor for the list of supported slots, the component props each one passes, and whether any slot is marked experimental. Treat a design that relies on an undocumented hook as a risk to price into the upgrade plan.
Whether the Task SDK is required
Check whether the feature needs task-side data. In Airflow 3, task code can no longer use the metadata database session or models directly, so any plugin logic that reads run state or writes to Airflow tables must go through the REST API or the Task SDK. Ask whether the plugin only renders views on the API server, or whether it needs to run inside task execution, because the second case changes the security review and the dependency footprint.
Support for your auth manager
Confirm that the plugin's access checks work with the auth manager you have chosen. Airflow 3 uses the Simple auth manager by default and allows only one auth manager at a time, set by the auth_manager option, so a plugin that assumes FAB roles or a custom permission model will not carry over. Ask how the plugin reads the current user, which permissions it checks, and what happens to a view when a user lacks the role that protects it.
Fit with your deployment model
Check how the plugin is packaged and loaded in your deployment. The community Helm chart and the official container image are the usual paths for Kubernetes, and a plugin must be present in every component that loads it, including the API server and any dependent services. Ask whether the plugin ships as a Python package baked into a custom image, how it is pinned, and whether the chart values you plan to use can mount or install it without a manual step on running pods.
How plugin behavior is tested in staging
Ask how the team verifies plugin behavior before a production change. A staging environment should run the same Airflow version, auth manager, database and image as production, and the test set should cover view rendering, permission denial, FastAPI route responses and middleware ordering. Confirm who owns the test suite, how it runs in CI, and how a failing plugin is rolled back without taking down the API server for other users.
Upgrade path for plugin code
Confirm how the plugin will be kept compatible across the next Airflow patch and minor releases. Ask which Airflow version the plugin was built against, whether its imports come from public packages, and who reviews the release notes for each upgrade. Plugins that rely on internal modules are the most likely to break, so request the list of internal imports and a plan for replacing each one before it is removed.
What teams ask before building Airflow plugins
How much effort does an Airflow plugin take to build?
Effort depends mostly on what the plugin does and how many systems it touches. A read-only external view that links operators to a dashboard is a small job. A React page that reads run data, calls the Airflow REST API, handles permissions and ships through your build pipeline is a larger one. The drivers are the number of screens, the data sources behind them, the authentication model, the amount of testing required, and whether the plugin must be packaged for several environments. Ask any partner to break the quote into design, build, tests, packaging, deployment and handover, and to state which items assume your existing CI pipeline and which require new tooling.
Can our in-house team build Airflow plugins without a partner?
Often yes, if the team already knows Python, FastAPI and, for the newer plugin system, React. The harder part is the Airflow-specific knowledge: which plugin keys are current, how plugins load in the API server, how the Task SDK and REST API replace direct database access in Airflow 3, and how permissions flow through the auth manager. Check three things before deciding: whether at least one engineer has shipped a plugin against Airflow 3, whether someone can review frontend and backend code, and whether the team can keep the plugin working through future Airflow minor releases. If any of these is missing, a fixed-scope build with a handover plan is one option to compare with hiring.
How long does migrating a Flask AppBuilder plugin take?
No general duration can be given here, because it depends on the plugin's size and how much of it relies on Flask-AppBuilder features. Airflow 3 requires FAB views, menu items and blueprints to be converted to FastAPI apps or run through the FAB provider's compatibility layer, so the first decision is which route fits each component. The duration is driven by the number of views and blueprints, custom templates and JavaScript, database access patterns that must move to the REST API or Task SDK, security and role checks, and the amount of test coverage that already exists. Ask for an inventory of each plugin component with a proposed route and a migration estimate per component.
What does the work need from our side?
The engagement needs named people and environments more than it needs large effort from your staff. Expect to provide the exact Airflow version you run, the Python and database versions, access to a non-production Airflow 3 environment that matches production in plugin loading and authentication, a copy of the existing plugin code and its tests, and a reviewer who knows your identity and access rules. You will also need a decision-maker who can approve the plugin's data sources and who signs off on the upgrade path. Ask the partner to list these inputs in the written scope so gaps show up before the build starts.
How do plugins affect the effort of each Airflow upgrade?
Plugins are one of the more common sources of upgrade work because they depend on internal APIs and UI structure that can change between releases. Each plugin adds a compatibility test to the upgrade, and a plugin that uses an extension point marked for change needs review in the same window as the core upgrade. Reduce this cost by keeping plugins on documented plugin keys, using the REST API rather than internal models, pinning tested versions, and running plugin tests in CI against each candidate Airflow version. Ask any partner how they will handle upgrade testing and whether it is included in the build or sold as a retainer.
What risks should we check before approving a plugin build?
The main risks are plugins that bypass authorization, plugins that expose data the viewer should not see, and plugins that add a second place where secrets or credentials are stored. For a plugin that runs on the API server, check how it authenticates users, which Airflow roles it respects, and whether its outbound calls use approved credentials. Also confirm who owns the code after handover and how a failed plugin is disabled without taking down the API server. Put these checks into the acceptance criteria so reviewers can test them directly.
Which questions should we put to a partner in a quote request?
Ask for the written scope to list each plugin component with its planned route, the Airflow and provider versions it targets, the test types included, and the acceptance criteria. Ask which items are one-time work, such as the build and handover, and which recur, such as upgrade testing or support. Ask how changes to scope are priced and approved, what the partner needs from your team in each phase, and what documentation you receive at the end. A quote that cannot explain these points is hard to compare with another quote or with your own team's estimate.
Official Airflow sources for plugin work
Start plugin work with the Airflow 3 upgrade guide, because it defines what changed for plugins before you write any code. It states that Flask-AppBuilder views, menu items and blueprints must be converted to FastAPI apps or run through the FAB provider's compatibility layer, and it names the preferred plugin keys: external_views, fastapi_apps and fastapi_root_middlewares. Read it against your current plugin manifest so you can list each existing plugin and mark which key or compatibility path it will need. The guide is the primary reference for that inventory: Upgrading to Airflow 3.
Next, read the Airflow release notes for the minor version you plan to run, since plugin behavior has moved between releases. The 3.1.0 notes cover the React plugin system (AIP-68), which is the feature most relevant to UI extensions. Confirm in those notes which plugin capabilities exist in the exact version your platform team will pin, and record that version in your plugin design document. Do not assume a feature from a later release is available on an older deployment. Release notes: Apache Airflow release notes.
Before you commit to a plugin design, confirm three things with your own team: which Airflow minor version is the upgrade target, whether any plugin depends on a Flask-AppBuilder view that cannot move cleanly to FastAPI, and who owns re-testing each plugin when Airflow is upgraded. Those answers determine whether the plugin work is a short conversion or a redesign, and they should appear in the written scope before any build starts.
How DeployOpen scopes and supports Airflow plugin work
DeployOpen plans, builds, documents and supports Apache Airflow UI plugins inside your own infrastructure, from the React plugin system and external views to FastAPI apps and middlewares. Engagements are fixed-scope, with the plugin inventory, compatibility targets and handover agreed in writing before build work starts.
How we scope
- Inventory every existing plugin, including any Flask AppBuilder views, menu items and blueprints that need conversion.
- Record which plugin keys each extension uses, such as external_views, fastapi_apps or fastapi_root_middlewares.
- Confirm the Airflow 3 minor version you run, and whether any plugin depends on the FAB provider compatibility layer.
How we build
- Build React plugin components against the Airflow 3 UI extension points for your target minor release, not against internal page markup.
- Write FastAPI apps and middlewares that call the Airflow REST API or Task SDK rather than database sessions or models.
- Test plugins against a staging Airflow instance that matches production in version, auth manager and database backend before release.
How we hand over
- Deliver source in your repository with build steps, dependency pins and a runbook for loading and disabling each plugin.
- Document the permissions each view or endpoint needs and how it maps to your auth manager roles.
- Provide an upgrade checklist that lists plugin changes to verify before moving to a newer Airflow 3 release.
How we support
- Re-test plugins during each planned Airflow upgrade, so UI and API changes surface before production users see them.
- Agree on a retainer for ongoing support, patch handling and continuous checks when plugins need steady maintenance.
- Confirm response expectations, ownership of plugin code and escalation paths in the written scope before work starts.

