Render
Run the node deploy target on Render as a managed Web Service built from the Dockerfile or a Node build.
Render is managed cloud for long-running web services. It runs the standard node deploy target - there is no Render-specific code in the boilerplate, just the same Dockerfile or Node build you would run anywhere.
Render is one long-running host for the node target - like Fly.io, Railway, Coolify, or Dokploy. Pick node at generatesaas init; both fullstack and separate architectures work here.
Deploy
Create a Web Service. In the Render dashboard, pick New → Web Service and connect your repository.
Choose the runtime. Select Docker so Render builds the owner app's Dockerfile - the frontend app's for fullstack, apps/backend/Dockerfile (EXPOSE 3010) for separate. A Node build also works if you prefer; the Dockerfile is the portable default.
Add environment variables. Set the required keys in the service's Environment tab (see the table below). They are validated at boot - the server throws if any are missing or malformed.
Attach a database and cache. Add a Render PostgreSQL instance (or any external DATABASE_URL). For the cache, the provider you chose at init decides the env vars: Redis (self-hosted) uses REDIS_URL (Render's own Key Value store fits here), while Upstash uses UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN. See Caching & Rate Limiting.
Deploy. Render builds the image and runs CMD pnpm start. The schema step the CLI prepended to the owner's start script runs first, applying migrations before the server boots.
Use the TLS domain. Render issues a managed *.onrender.com URL with TLS, or you can attach a custom domain. Set that origin as API_URL / BASE_URL and add it to TRUSTED_ORIGINS.
Required environment variables
Set these on the service before the first deploy - validated at boot by @repo/runtime (packages/runtime/src/env.ts).
| Variable | Purpose |
|---|---|
DATABASE_URL | Postgres connection; required by the boot-time schema step |
BETTER_AUTH_SECRET | Auth signing secret (min 32 chars) |
API_URL | The backend's public URL (your Render domain) |
REDIS_URL | Cache connection - only on the self-hosted Redis variant. The Upstash variant uses UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN instead |
INNGEST_APP_ID | Background-jobs app identifier |
INNGEST_EVENT_KEY | Background-jobs event key |
INNGEST_BASE_URL | Background-jobs endpoint URL |
TRUSTED_ORIGINS | Comma-separated production domains for CORS + Better Auth trusted origins |
See Environment variables for the full list.
Database and cache options
In production you supply your own data services. Pick a Render-hosted option or point at an external managed provider.
The cache provider is fixed at init - set the env vars for that variant only, never both.
| Service | Render-hosted | External managed |
|---|---|---|
| Postgres | Render PostgreSQL → DATABASE_URL | Neon or Supabase → DATABASE_URL |
| Cache (Redis variant) | Render Key Value → REDIS_URL | self-hosted Redis → REDIS_URL |
| Cache (Upstash variant) | - | Upstash → UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN |
Never pass --demo for a real deployment. The schema step becomes a destructive reset && push --force that wipes the database on every boot.
There is no pnpm infra step here - infra/docker-compose.yml is for local development only. On Render the database and cache are managed services you attach, not containers you start.
Next steps
Self-hosting with Docker
How the multi-stage image is built and the schema step runs on boot.
Separate backend
Run the standalone Hono server on API_PORT for independent scaling.
Reverse proxy
Front multiple long-running apps by host and path.
Going to production
The full pre-launch checklist before you ship.