GenerateSaaS

Separate Backend

Run @repo/api as a standalone Hono server on API_PORT with its own scaling, trusted origins, and host.

In separate architecture apps/backend/src/index.ts serves @repo/api via @hono/node-server on API_PORT as its own process. Choose it over fullstack when the API needs to scale, deploy, or fail independently of any frontend.

When to choose separate

ReasonWhy separate helps
Independent scalingScale the API and frontend on different curves
Multiple frontendsOne API serves many origins - web, mobile, partner apps
Operational isolationA frontend deploy or crash cannot take the API down

If none apply, fullstack is simpler: fewer hosts, no CORS, no API_URL.

The standalone entry point

const apiServer = serve({ fetch: app.fetch, port: env.API_PORT });
// SIGINT / SIGTERM -> closeRedis(), then apiServer.close()
  • Listens on API_PORT (default 3010).
  • Closes the Redis connection, then drains the server on SIGINT/SIGTERM.
  • A fatal bootstrap error exits with code 1.

separate deploys only to a long-running host - Docker on Render, Fly.io, Railway, Coolify, Dokploy, or a VPS. The CLI blocks separate + vercel: a graceful-shutdown process cannot run as serverless functions.

Wiring frontend to backend

Both sides need configuring before any browser call succeeds.

Backend - set TRUSTED_ORIGINS (comma-separated, no trailing slash) to every frontend origin. It becomes config.origins, which CORS and auth enforce. Unset, it falls back to localhost:3000, :3001, :5173, and every browser call is rejected in production.
Frontend - point the API client at the backend base URL (e.g. https://api.yourdomain.com) via NEXT_PUBLIC_API_URL.
Front both apps with a proxy by host or path. See Reverse proxy.
VarSidePurpose
API_PORTBackendPort the standalone server binds (default 3010)
TRUSTED_ORIGINSBackendComma-separated allowed origins → config.origins
API_URLBackendValidated runtime base URL; falls back to the frontend's public API URL var
NEXT_PUBLIC_API_URLFrontendPublic API URL the client targets - set to the backend base URL

Switching architecture later needs no CLI re-run: the API code is identical, only the host and env vars differ. Follow Switch to separate or Switch to fullstack - both rewire in place and preserve your customized packages/config and .env, which re-running the CLI would regenerate wholesale.

On this page