Skip to main content
Multi-service apps share a single hostname. floo routes requests to the right service based on path prefix.

Default path assignment

These defaults apply when the app does not declare [[routes]]. Only web and api service types get public gateway routes. worker services have no public route; they are internal only. A full-stack app with a web and api service gets:
  • https://full-stack.getfloo.app/ → web
  • https://full-stack.getfloo.app/api/ → api
The web service is the catch-all: any path not matched by a more specific prefix falls through to it.

Why same origin matters

All services share one hostname, so cookies and session tokens set by the web service are visible to the api service with no CORS headers or other cross-origin configuration. Services on different domains need CORS configuration and must handle cross-origin cookie restrictions.

Per-service debug hostnames

Each service also gets its own hostname for direct access, which includes the environment: Use them to debug one service or to connect external tools directly to it.

Explicit service routes

Declare [[routes]] in floo.app.toml to select a service and access policy by path. Every entry must name a declared public-ingress web or api service; include an explicit / catch-all. Worker and internal service targets are rejected. An explicit table replaces the defaults on every app hostname, including service aliases and verified custom domains. With this configuration, a service hostname is an alias of the whole app table, not direct access to that service. This prevents an alternate hostname from bypassing a protected path. Prefixes are not stripped before forwarding. The routing table comes from the deployed floo.app.toml and the services that deploy created. Restart and rollback preserve that deployed policy; another environment’s mutable service URL does not change it. Removing the declarations restores conventional routing. See App API keys and request history for an ACCOUNTS browser route alongside a scoped API_KEY integration path.

Custom domains

Declare a host in floo.app.toml and name its target service:
Without explicit [[routes]], a custom domain routes directly to its assigned service. With explicit routes, it serves the same complete table as the app host. Release to prod and publish the traffic and certificate DNS records printed by floo. Activation is automatic. See Custom domains for DNS setup.

Local development

Under floo dev, each service runs on its own localhost port, and floo injects a <SERVICE>_URL discovery var for each service (API_URL for a service named api) so services find each other without hardcoded ports. See floo dev for the full local dev reference.

localhost fallback diagnostics

Source validation treats localhost URLs as non-blocking warnings:
  • A localhost URL behind an explicit Node or Vite development guard does not emit a warning.
  • A runtime-configured URL that may fall back to localhost emits unverified_localhost_fallback. floo cannot verify the production value from source alone.
  • A localhost URL without a recognized development-only guard emits hardcoded_localhost_fallback.
For production service-to-service calls, use the injected discovery variable such as API_URL or a relative gateway path such as /api. Keep a localhost default behind an explicit development-only guard.

Limitations

  • WebSockets use the same route table as HTTP. WebSocket upgrade requests route to public web and api services by host and path prefix.
  • Only web and api service types are routable. worker services are internal and have no public gateway route.