Separate Backend
Run the Hono API as a standalone server with its own scaling, 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
| Reason | Why separate helps |
|---|---|
| Independent scaling | Scale the API and frontend on different curves. |
| Multiple frontends | One API serves many origins (web, mobile, partner apps). |
| Operational isolation | A frontend deploy or crash can't take the API down. |
If none of these apply, fullstack (the frontend hosts @repo/api in-process) is simpler - fewer hosts, no CORS, no API_URL.
The standalone entry point
apps/backend/src/index.ts boots one Hono server with graceful shutdown:
const apiServer = serve({ fetch: app.fetch, port: env.API_PORT });
// SIGINT / SIGTERM -> closeRedis(), then apiServer.close()- Listens on
API_PORT(default3010). - Closes the Redis connection, then drains the server on
SIGINT/SIGTERM. - A fatal bootstrap error exits with code
1.
Long-running host only
separate deploys only to a long-running host (Docker on Render, Fly.io, Railway, Coolify, Dokploy, or a VPS). The CLI blocks separate + vercel with INCOMPATIBLE_ARCH_TARGETS - a graceful-shutdown process can't run as serverless functions.
Wiring frontend to backend
Cross-origin requests need both sides configured before any browser call succeeds.
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.https://api.yourdomain.com). The exact key carries a framework prefix - see your framework's env reference.| Var | Side | Purpose |
|---|---|---|
API_PORT | Backend | Port the standalone server binds (default 3010). |
TRUSTED_ORIGINS | Backend | Comma-separated allowed origins → config.origins. |
API_URL | Backend | Validated runtime base URL; falls back from the frontend's public API URL var. |
*_PUBLIC_API_URL | Frontend | Framework-prefixed public API URL the client targets - set to the backend base URL. |
Frequently asked questions
Do I need a reverse proxy?
Yes for production - route the root domain to the frontend and api.yourdomain.com (or yourdomain.com/api/) to the backend. See Reverse proxy.
What happens if TRUSTED_ORIGINS is wrong?
CORS and auth reject every browser call. List each real frontend origin exactly, with no trailing slash.
Can I switch architecture later?
Yes - the API code is identical; only the host and env vars differ. Follow Switch to separate (or back to fullstack) - an in-place rewiring that preserves your customized packages/config and .env. Don't re-run the CLI; it regenerates both wholesale.