Fly.io Provider

Deploy preview environments to Fly.io using the Machines REST API.

How it works

Everything runs in your own Fly account — Previewops does not use its own infrastructure for builds or storage.

Prerequisites

  1. A Fly.io account and organisation.
  2. Your Fly organisation must support privileged machines — required for the Docker builder. Most Fly orgs have this by default. If you see a permission denied error on the first build, contact Fly support to enable it.

Step 1 — Create a Fly API token

fly tokens create deploy --name previewops

Copy the token — you will need it in Step 3.

Step 2 — Find your org slug

fly orgs list

The slug is in the Slug column (e.g. personal or my-company).

Step 3 — Store credentials in Previewops

Navigate to Dashboard → Credentials and add the following keys under the Fly.io provider:

Key Required Value
FLY_API_TOKEN Token from Step 1
FLY_ORG_SLUG Org slug from Step 2 (e.g. my-fly-org)
FLY_REGION Fly region code (default: iad). Run fly platform regions to list options.

Once stored, you can comment /deploy-previewops --provider=fly on any PR — no .previewops.yaml file is required.

Step 4 — Configure the repo (optional)

If you need per-repo overrides, add .previewops.yaml to the repo root:

provider: fly
providerConfig:
  orgSlug: my-fly-org   # overrides FLY_ORG_SLUG credential
  region: iad           # overrides FLY_REGION credential

Values in .previewops.yaml always take precedence over the credentials stored in Step 3.

Step 5 — Verify

Comment /validate-previewops on any open PR. The bot will confirm your token is valid and your org is reachable.

Build times

Scenario Typical duration
First build (no cached layers) 5–15 minutes
Subsequent builds (dependencies unchanged) 2–5 minutes

The main variable is your Dockerfile — specifically how long docker build takes for your dependencies. Build progress is polled every 15 seconds, so the reported duration may be rounded up slightly.

Tip: structure your Dockerfile so dependency installation (COPY package.json && npm install) comes before copying your source files (COPY . .). Docker caches each layer, so unchanged dependencies won't be reinstalled on subsequent builds.

Dockerfile requirements

Notes

Troubleshooting

Error Cause Fix
FLY_API_TOKEN environment variable is required Token not stored Add FLY_API_TOKEN in Dashboard → Credentials
fly orgSlug is required Org slug missing Add FLY_ORG_SLUG credential or orgSlug in .previewops.yaml
401 Unauthorized from Fly API Token expired or invalid Regenerate: fly tokens create deploy --name previewops
permission denied on first build Privileged machines not enabled for your org Contact Fly support
IP allocation failed — no shared_v4 found Transient Fly API timing issue Retry the deploy — this resolves on its own
Your application crashed immediately after startup App process exited at boot See App crashes on startup
Build timed out after 3600s Build exceeded 1 hour Check your Dockerfile for unusually slow steps; ensure the base image is accessible
Preview machine did not reach 'started' state Machine start timed out (60s) Retry; if persistent, check your Fly org's machine quotas
Build failed with empty package directories Build environment compatibility issue See Build fails with empty package directories
Build marked ❌ Failed on first attempt with no clear error Build infrastructure was interrupted mid-run See Build fails on first attempt

Build fails on first attempt

Occasionally a build will fail on the first /deploy-previewops --provider=fly attempt even when your Dockerfile and credentials are correct. This can happen when the remote build environment is interrupted before the build completes — typically on the very first deploy to a new Fly org or after a long period of inactivity.

Simply retry the command. The second attempt provisions fresh build infrastructure and should complete successfully.

If builds fail consistently across multiple retries, check the build output for a specific error message and consult the table above.

Build fails with empty package directories

If your build fails and your package manager appears to have run but produced no output files, ensure your Dockerfile uses standard copy operations without requiring special filesystem capabilities. Previewops automatically selects the most compatible build mode for Fly — no configuration change is needed on your side.

If the issue persists, try adding a RUN echo "build ok" after your install step to confirm which layer is failing, then share the build output with Previewops support.

App crashes on startup

When the bot posts "Your application crashed immediately after startup", the preview machine started successfully but your app process exited before it could accept connections.

Common causes by exit code:

Exit code Likely cause
1 Unhandled exception or startup error — check your application logs
127 Command not found — a dependency or binary is missing from the image
137 Out of memory — increase memory in .previewops.yaml
? Very fast crash before the exit code was recorded

Debugging steps:

  1. Confirm your app starts locally with Docker:
    docker build -t test . && docker run -e PORT=3000 -p 3000:3000 test
    
  2. Confirm your app reads PORT from the environment and listens on that port. Previewops sets PORT automatically.
  3. If exit code 137 (OOM), increase memory in .previewops.yaml:
    memory: 1Gi   # default is 256Mi
    
  4. Check your Dockerfile CMD/ENTRYPOINT — ensure it starts the server and does not exit immediately.

Token permissions

The deploy token scope (created via fly tokens create deploy) is sufficient for all Previewops operations. You do not need an admin or org-owner token.

If you rotate your Fly API token, update it in Dashboard → Credentials and re-run /validate-previewops to confirm the new token works before triggering a deploy.

Prerequisites

  1. A Fly.io account.
  2. A Fly organisation (personal accounts use your username as the org slug).
  3. The org must support privileged machines — required for the Docker-in-Docker builder. Verify with fly platform vm-sizes or by contacting Fly support if you hit a restriction.

Step 1 — Create a Fly API token

fly tokens create deploy --name previewops

Store the output as FLY_API_TOKEN in Previewops secrets.

Step 2 — Find your org slug

fly orgs list

The slug is the value in the Slug column (e.g. personal or my-company).

Step 3 — Store secrets in Previewops

Navigate to Dashboard → Credentials and add the following keys for the Fly.io provider:

Key Required Value
FLY_API_TOKEN Token from step 1
FLY_ORG_SLUG Org slug from step 2 (e.g. my-fly-org)
FLY_REGION Fly.io region code (default: iad) — see fly platform regions

Once all three keys are stored, you can simplify or eliminate your .previewops.yaml:

Step 4 — Configure the repo (optional)

If you need per-repo overrides (e.g. a different org or region per repo), add a .previewops.yaml to the repo root. Values here take precedence over the credential keys stored in step 3.

provider: fly
providerConfig:
  orgSlug: my-fly-org   # overrides FLY_ORG_SLUG credential
  region: iad           # overrides FLY_REGION credential

If all values are stored as credentials (step 3), this file is optional.

Step 5 — Verify

Comment /validate-previewops on any open PR. The bot calls the Fly API and confirms the token is valid and the org exists.

Build times

Build Typical duration
First build (cold cache) 5–10 minutes
Subsequent builds (warm cache) ~1–2 minutes

The builder machine is stopped (not deleted) after each build, so Docker layer cache is preserved. The main variables are your app's docker build time and how long docker push takes over Fly's network. PreviewOps polls for build completion every 15 seconds, so the total time reported may be rounded up to the next poll interval.

Notes

Troubleshooting

Error Fix
FLY_API_TOKEN environment variable is required Set the token in Previewops credentials
fly orgSlug is required Add FLY_ORG_SLUG credential or orgSlug to providerConfig in .previewops.yaml
401 Unauthorized from Fly API Token expired — regenerate with fly tokens create deploy
Build fails with permission denied The Fly org may not allow privileged machines — contact Fly support