https://<app>.on.getfloo.com, with managed Postgres, signed-in users, and your own domain.
New to floo? Start with the Quickstart.
Before you start
You need:- A Next.js 14+ App Router project (or a fresh
npx create-next-app@latest). - The project pushed to a GitHub repository. floo pulls source from GitHub; it does not upload local files.
- The floo CLI installed and authenticated (
curl -fsSL https://getfloo.com/install.sh | bashthenfloo auth login). - The floo GitHub App installed on the account that owns the repository.
floo apps github connectopens a browser to install it if it is missing.
1. Add a Dockerfile
Configure Next.js for standalone output (much smaller container):next.config.js
Dockerfile
2. Build-time env vars (NEXT_PUBLIC_*)
Any NEXT_PUBLIC_* variable referenced in your code is baked into the JS bundle at build time, not read at runtime. floo passes every env var whose name starts with NEXT_PUBLIC_, VITE_, or REACT_APP_ to the image build as a Docker build arg, and injects it at runtime as well. Two things have to line up.
First, set the value as an ordinary env var. No extra flag is needed; the name prefix is what makes it a build arg.
ARG makes Docker accept the value; the ENV line is what puts it in process.env for next build.
Dockerfile
undefined baked in. The build step records a diagnostic when a build-time var is passed but not threaded into the stage that runs next build.
Env vars are per environment (--env dev is the default). A promote rebuilds the image with prod’s values whenever prod has any NEXT_PUBLIC_/VITE_/REACT_APP_ var, and otherwise reuses the dev image with the dev values baked in, so set the var in both environments when the values differ:
/api/...) avoid the question entirely. See Container contract and Environment variables.
3. Initialize the floo config
floo.app.toml
migrate_command runs as a one-off job with the new image. Release promotion
without rebuilding runs it before any application revision changes and blocks
promotion if it fails. Fresh deploys run it after deploying the new revisions:
with traffic staging enabled, migration precedes cutover; without staging, new
code can serve before migration runs. Use
expand-then-contract migrations
to keep the schema compatible with both old and new code.
4. Connect the repo and deploy
Your Next.js app is live at
https://my-nextjs-app-dev.on.getfloo.com.Every git push origin main ships to dev. floo releases promote --app my-nextjs-app publishes to https://my-nextjs-app.on.getfloo.com.5. Add a Postgres database
floo.app.toml
DATABASE_URL is injected into the runtime. With Prisma:
prisma/schema.prisma
migrate_command, the next deploy runs npx prisma migrate deploy against the new database. Migration and traffic ordering depend on the deploy path; use expand-then-contract migrations.
6. Add per-user auth
floo manages user authentication for you. Setaccess_mode = "accounts" in floo.app.toml:
floo.app.toml
- Redirects unauthenticated requests to a hosted login page.
- Validates the session cookie on every request.
- Injects identity headers into every request that reaches your Next.js app.
app/dashboard/page.tsx
floo dev --fixture-user (see section 8) or hit your dev server with curl -H 'X-Floo-User-Email: you@example.com'.
For the full reference on access modes and identity headers, see Auth.
7. Add a custom domain
Declare the domain infloo.app.toml:
show at your DNS
provider, then watch activation:
Host and X-Forwarded-Host from the request, with no extra config needed.
8. Local development with dev credentials
dev_command locally with DATABASE_URL and the other env vars from the app’s dev environment: a real connection to your dev Postgres, with no credentials in your shell history. Prod credentials are never handed to a local session.
To also test signed-in flows for this accounts-mode app, add --fixture-user:
floo dev then starts a small proxy in front of each service that injects the same X-Floo-User-* headers floo’s gateway adds in production. The output table shows both the raw service URL and the auth-proxied URL. Hit the auth-proxied one for any path that reads identity headers.
Common gotchas
/healthzis reserved. floo’s edge intercepts that exact path. Use/healthor/livez.HOSTNAME=0.0.0.0. Next.js standalone defaults tolocalhost, which floo cannot reach.NEXT_PUBLIC_*build args. Set them withfloo env setand thread them through the build stage asARGplusENV. Otherwise the bundle hasundefinedbaked in.output: "standalone"innext.config.js. The Dockerfile above assumes standalone output. Without it, the build artifact is much larger and theCOPY --from=build /app/.next/standaloneline fails.- A
.dockerignorelistingnode_modules.COPY . .runs after the clean install is copied in, so without one your localnode_modulesoverwrites it.
What’s next
Auth, full reference
Identity headers, access policies, and access modes in detail.
Multi-service routing
Deploy Next.js alongside a FastAPI or Express backend with shared origin.
Environment variables
Build-time vs runtime env vars, secrets, and per-service scoping.
Custom domains
DNS, verification, multi-service routing.