Skip to main content

Serverless Airflow Executor on Modal

Project description

Modalflow

A serverless Airflow executor that runs tasks as Modal Functions.

Modalflow replaces Airflow's built-in executors (Local, Celery, Kubernetes) with one that dispatches each task to a Modal Function. No worker pools, no Kubernetes cluster, no infrastructure to manage — tasks run on-demand and scale to zero when idle.

Prerequisites

  • An existing Airflow 3.1+ deployment
  • A Modal account with the CLI configured (modal setup)
  • Python 3.10+

Setup

1. Install

Install modalflow on both your local machine (for the CLI) and your Airflow cluster (for the executor):

pip install modalflow

2. Deploy the Modal backend

The modalflow deploy command creates the Modal Function, Volume, and Dict that the executor needs. You must choose how DAG files are provided to the Modal task workers:

Local mode — bakes DAGs into the function image (simplest, but requires redeploying on every DAG change):

modalflow deploy --dags-source local --dags-path ./dags

Volume mode — stores DAGs on a Modal Volume (update DAGs without redeploying):

modalflow deploy --dags-source volume --dags-volume my-dags --dags-path ./dags

Cloud bucket mode — reads DAGs from an S3 bucket at runtime:

modalflow deploy --dags-source cloud-bucket \
  --dags-bucket s3://my-bucket/dags \
  --dags-bucket-secret my-aws-secret

By default, the Modal function image installs Airflow 3.1.5. To match your local Airflow version, use --airflow-version:

modalflow deploy --dags-source local --dags-path ./dags --airflow-version 3.1.8

To target a specific Modal environment, add --env <name> (default: main).

3. Configure Airflow

Set the executor class in airflow.cfg or via environment variable:

[core]
executor = modalflow.executor.ModalExecutor
export AIRFLOW__CORE__EXECUTOR=modalflow.executor.ModalExecutor

The executor reads MODALFLOW_ENV to find the right Modal app (default: main). Set it if you deployed with a custom --env.

Updating DAGs (volume mode)

With volume mode, use modalflow sync to push DAG changes without redeploying the function:

modalflow sync --dags-path ./dags --dags-volume my-dags

This does a full replace — files deleted locally are also removed from the volume.

Networking

Modal Functions run in Modal's cloud. To execute a task, the function must call back to your Airflow deployment's execution API. This means Airflow's API server must be reachable from the public internet.

The executor resolves the execution API URL in priority order:

  1. AIRFLOW__CORE__EXECUTION_API_SERVER_URL environment variable
  2. core.execution_api_server_url in airflow.cfg

The URL must end with /execution/ — the executor appends this automatically if missing. See apache/airflow#51235 for background.

Production

Set the URL to your Airflow API's public endpoint:

export AIRFLOW__CORE__EXECUTION_API_SERVER_URL=https://airflow.example.com/execution/

Common ways to expose the API:

  • Load balancer (ALB, NLB) in front of the Airflow API server
  • API Gateway with auth
  • Reverse tunnel (Cloudflare Tunnel, ngrok) if you can't expose a public endpoint directly

Local development

When running Airflow locally (e.g. airflow standalone), Modal functions need to reach your local execution API. Use a reverse tunnel (ngrok, Cloudflare Tunnel, etc.) and set the URL:

export AIRFLOW__CORE__EXECUTION_API_SERVER_URL=https://your-tunnel-url.ngrok-free.app/execution/

See .env.example for a full local development template.

Important: deploy with --airflow-version matching your local Airflow version to avoid API version mismatches between the SDK on Modal and your local Airflow server:

modalflow deploy --dags-source local --dags-path ./dags --airflow-version 3.1.8

Note: Only DAGs you deploy to Modal (via --dags-path) are available to task workers. Airflow's built-in example DAGs use a separate bundle (example_dags) that isn't present on Modal, so they will fail. Use your own DAGs.

Development

uv sync --extra dev
uv run modalflow deploy --help
uv run pytest                      # unit tests
make system.setup && make system.test.e2e   # E2E tests (requires Modal)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

modalflow-0.3.0.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

modalflow-0.3.0-py3-none-any.whl (13.4 kB view details)

Uploaded Python 3

File details

Details for the file modalflow-0.3.0.tar.gz.

File metadata

  • Download URL: modalflow-0.3.0.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for modalflow-0.3.0.tar.gz
Algorithm Hash digest
SHA256 8780da03fad1fb101b869c1da3c9f4ee90ee5035e1a2f78ed9772f073a5c57b9
MD5 4db9359b7ba2cbe41a90f7fb344c87f6
BLAKE2b-256 fc6aea50ed575da0190316b7b082da4d869c8245bb9f0860bc96c0fc21708568

See more details on using hashes here.

Provenance

The following attestation bundles were made for modalflow-0.3.0.tar.gz:

Publisher: publish.yml on agupta01/modalflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file modalflow-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: modalflow-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 13.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for modalflow-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4ca846c47afc24401cecad33229ff1218c53df03e31225af3fad692468ce72aa
MD5 1b720ec19264988d7d198ca163615541
BLAKE2b-256 6ee7766b8492737b234d4c9ce918611984cf432a94529dd90db711253912e1b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for modalflow-0.3.0-py3-none-any.whl:

Publisher: publish.yml on agupta01/modalflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page