Skip to main content
floo builds the Dockerfile in your service directory and runs the image. These are the requirements that image must meet. floo preflight checks most of them 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 and waits for a response that is not a 5xx. A service that is still booting when the window closes does not fail the deploy: the deploy still goes live, the health-check step records a warning, and the health_check_timeout diagnostic tells you which URL never answered. Traffic reaches the new revision either way, so a slow boot is served as errors until the container comes up. Move slow work out of startup. Run migrations through migrate_command rather than 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. The deploy’s 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. It cannot reach another one. For service-to-service calls use the 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. For a workspace repository that is not enough: 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. What a non-zero exit does depends on the lane: on a dev deploy it is recorded as the migration_failed diagnostic and the rollout continues; on a promote with no build-time env vars in prod, the migration runs before any prod revision changes and a failure marks the deploy FAILED with production traffic left where it was; on a promote that rebuilds because prod has build-time env vars, a failure is only logged. Shipping code that expects tables nothing created fails with missing_migrate_command.

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, not by preflight.