uvx synth-ai deploy --runtime modal. It packages the exact task app you validated locally, uploads any necessary code, injects secrets, and runs modal deploy or modal serve via the Modal CLI. The first *.modal.run URL produced by the CLI is automatically written to your .env as TASK_APP_URL, so Synth trainers and smoke tests can target the deployed service immediately.
Why Modal?
- Durable HTTPS endpoint with GPU/CPU scale and zero local infrastructure.
- Identical code paths to local development (your repo is mounted into the Modal image).
- Automatic secret handling: the CLI injects
ENVIRONMENT_API_KEYas an inline ModalSecret, so the remote app keeps auth parity with local testing.
Prerequisites
- Complete
uvx synth-ai setupso bothSYNTH_API_KEYandENVIRONMENT_API_KEYare available (from.envor your environment). - Install the Modal CLI (
pip install modal-clientorbrew install modal-labs/homebrew-tap/modal). - Log in once: the deploy command will prompt you, but you can pre-run
modal setupto cacheMODAL_TOKEN_ID/MODAL_TOKEN_SECRET. - Create a Modal app file that exposes
app = modal.App("my-task-app")(or importsAppdirectly). The CLI’svalidate_modal_apprejects files without a literal app name so deployments always have a stable identifier.
Preview with modal serve
Use --modal-mode serve for an interactive container that mirrors the local runtime but runs inside Modal’s infrastructure:
- The CLI spawns a temporary wrapper module that adds your repo and task-app directory as local mounts inside the Modal image, so imports continue working without publishing a wheel.
ENVIRONMENT_API_KEYis converted into a Modal inline secret and attached to every function decorator that already referencesmodal.Secret(...). You still need to register other secrets normally (or pass them via--env).modal serveblocks your terminal and tears down when you exit—ideal for rapid iteration or debugging Modal-specific behavior before promoting to a full deploy.
Launch a production deploy
- The CLI validates both the FastAPI task app and the Modal app file.
ModalDeployCfgresolves the Modal binary (or respects--modal-cli PATH), enforces that--dry-runis only available with--modal-mode deploy, and raises clear errors if the CLI is missing.deploy_app_modalrunsmodal deploywith a temporary wrapper, streams CLI output, and captures the first*.modal.runURL.- The URL is saved to
.envasTASK_APP_URL, so you can immediately runuvx synth-ai smoke --url "$TASK_APP_URL".
Useful flags
| Flag | Description |
|---|---|
--name | Override the Modal app name. Default is whatever literal string you used in modal.App(...). |
--modal-cli PATH | Point to a custom Modal binary (helpful when using uv tool install modal). |
--dry-run | Print the exact Modal CLI command instead of executing it (deploy mode only). |
--env PATH | Load additional .env files; secrets found there are inlined before uploading. |
Note:--modal-mode servecannot be combined with--dry-run, and MCP-based executions block dry runs entirely for safety.
After deployment
-
Sanity check the service:
curl -H "X-API-Key: $ENVIRONMENT_API_KEY" "$TASK_APP_URL/health". -
Record the URL in your RL or prompt-optimization configs (e.g.,
task_app_url = "https://my-task-app.modal.run"). -
Optionally re-run the local smoke test against the Modal URL:
- Any time you change code, rerun the same deploy command; Modal takes care of building the image, uploading differences, and recycling the container.