Skip to main content
floo builds each service’s Dockerfile and runs the image, which must meet the requirements below. floo preflight checks the ones it can verify statically before you push.

Bind $PORT on 0.0.0.0

floo sets PORT in the environment and routes to it. A fixed port or a bind to 127.0.0.1 makes the container unreachable and the deploy fails with port_mismatch.

Answer at your route root within 60 seconds

After each deploy, floo polls every routed service at its own path-prefixed URL for up to 60 seconds, waiting for any response that is not a 5xx. A service still booting when the window closes does not fail the deploy: the deploy goes live, the health-check step records a warning, and the health_check_timeout diagnostic names the URL that never answered. Traffic reaches the new revision either way, so a slow boot serves errors until the container is up. Move slow work out of startup, and run migrations through migrate_command, not on boot.

/healthz is reserved

The serving edge upstream of floo’s gateway answers that exact path with a 404 before the request reaches the gateway or your container. A handler bound to it is unreachable. Use /health or /livez. Deploy config validation reports a /healthz route in your source as the reserved_path_healthz diagnostic.

Thread build args into the build

A build arg is not an environment variable. Forward it in the same stage, before the build step, or the value is empty at build time and bakes undefined into your bundle.
floo passes every env var named NEXT_PUBLIC_*, VITE_*, or REACT_APP_* to the build as a build arg and also injects it at runtime. Set them with floo env set; there is no separate build-arg flag or config key. See Build-time variables.

No unguarded localhost fallbacks

Inside a deployed service, localhost is that service and cannot reach another one. For service-to-service calls use an injected discovery variable such as API_URL, or a relative gateway path such as /api. Keep any local default behind an explicit development-only guard.

Know which directory is your build context

By default the build context is the service’s own path, and the Dockerfile must sit inside it. A service at path = "./api" builds with ./api as its root and cannot read files above it. In a workspace repository, a service at ./apps/web cannot reach a sibling packages/, so pnpm install cannot resolve workspace:*. Set dockerfile to move the context to the repository root:
floo.app.toml partial
COPY paths in that Dockerfile are then written from the root. See Monorepos.

Run migrations through migrate_command

Set migrate_command on the service that owns the schema. floo runs it as a one-off job against the target environment before shifting traffic to the new revision. Push deploys, CLI promotion, and GitHub-release promotion all stop on migration failure and leave the previous live revision serving. An explicitly requested floo redeploy --rebuild --skip-migrations skips this step. The old revision can serve the migrated schema until cutover, or longer if rollout fails. Use expand-then-contract migrations and keep both versions compatible. floo does not undo database writes from a failed migration. Source checks report missing_migrate_command when migration files exist without a configured command; that warning does not run them.

Keep the build small

Builds run with bounded memory and fail with build_oom when they exceed it. Use multi-stage builds and copy only the built output into the final stage.

Checking your image

Preflight validates config and scans your source for the rules above that can be checked statically. Port binding is verified at deploy time.