Skip to main content
This guide walks an Express 4/5 app from local code to a production URL with a database and per-user auth. Every step has runnable JavaScript code. By the end you have a working app at https://<app>.on.getfloo.com with a Postgres sibling service, signed-in users, and (optionally) your own domain. If you’ve never deployed to floo before, read Golden Path first for the minimal three-command flow.

Before you start

You need:
  • An Express project (or npm init -y && npm install express).
  • The project pushed to a GitHub repository.
  • The floo CLI installed and authenticated (curl -fsSL https://getfloo.com/install.sh | bash then floo auth login).

1. Add a Dockerfile

Dockerfile
Bind to 0.0.0.0, not localhost. Cloud Run only routes traffic to processes bound to all interfaces.

2. Trust the proxy

floo’s edge sits in front of your Express app. Tell Express to trust it so req.protocol, req.hostname, and req.ip reflect the original client request:
server.js

3. Initialize the floo config

floo.app.toml

4. Connect the repo and deploy

Your Express app is live at https://my-express-app-dev.on.getfloo.com.

5. Add a Postgres database

floo.app.toml
DATABASE_URL is injected. With pg:
db.js
Or use Prisma (npx prisma init); Prisma reads DATABASE_URL from the environment automatically.

6. Add per-user auth

floo manages user authentication for you. Set access_mode = "accounts" in floo.app.toml:
floo.app.toml
Push and deploy. From the next deploy onward, floo’s gateway sits in front of your app and:
  • Redirects unauthenticated requests to a hosted login page.
  • Validates the session cookie on every request.
  • Injects identity headers into every request that reaches your Express app.
Read the headers in any handler:
server.js
For local development, send the headers yourself or extend the middleware to inject a fixture user when they’re missing. For the full reference on access modes and identity headers, see Add User Auth to Your App.

7. Add a custom domain

Add the traffic and _floo-verify TXT records shown at your DNS provider, then run floo domains verify app.example.com --app my-express-app. With app.set("trust proxy", true), Express reads req.hostname from X-Forwarded-Host automatically, with no extra config needed.

8. Local development with prod data

Runs dev_command locally with DATABASE_URL and other env vars sourced from your dev floo app — real Cloud SQL connection, no credentials in your shell history. 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

  • /healthz is reserved. Cloud Run’s edge intercepts that exact path. Use /health or /livez.
  • Bind to 0.0.0.0. Express defaults to 0.0.0.0 only when you pass it explicitly to app.listen(port, "0.0.0.0", ...). Without it some setups bind to localhost.
  • app.set("trust proxy", true) is required. Without it, req.protocol is always http, secure cookies don’t get set, and req.ip is wrong.
  • ESM vs CommonJS. The examples use ESM (import/export). For CJS, use require() and module.exports equivalently — the logic is identical.

What’s next

Add User Auth — full reference

Identity headers, access policies, and access modes in detail.

Managed Services

Postgres, Redis, Storage — what they cost and how isolation works.

Multi-Service Routing

Deploy Express alongside a Next.js or React frontend with shared origin.

Custom Domains

DNS, verification, multi-service routing.