Deploy Node.js, Next.js and Nuxt
This guide deploys a server-rendered JavaScript or TypeScript app — Express, Fastify, Hono, NestJS, Next.js, Nuxt, Remix, SvelteKit, Astro SSR — to Falak. The app runs as a supervised process on each server, and Caddy terminates TLS and proxies to it.
Prerequisites
Section titled “Prerequisites”- A server of type app, web or worker with Node.js (the default server stack installs Node 22).
- A
package.jsonwith:- a
startscript — Falak runsnpm run startin the release; - a
buildscript if your app needs one (Next.js, Nuxt, TypeScript).
- a
- Your app listens on
process.env.PORT(and ideallyprocess.env.HOST).
import http from 'node:http';
const port = Number(process.env.PORT ?? 3000);const host = process.env.HOST ?? '127.0.0.1';
http.createServer((req, res) => res.end('Hello from Falak')).listen(port, host);{ "scripts": { "build": "tsc -p .", "start": "node dist/server.js" }}Deploy
Section titled “Deploy”- + Create → Git repository, choose the repository and branch.
- Falak detects the stack and suggests Next.js, Nuxt or Generic Node. The runtime is Node.js.
- Pick servers and a domain, then click Deploy.
- The build installs dependencies, runs
build, prunes dev dependencies and uploads the release. Each server starts the web process and Caddy proxies the domain to it.
How it runs
Section titled “How it runs”| Aspect | Value |
|---|---|
| Web process | <slug>.app, supervised by the agent: npm run start in /srv/falak/sites/<slug>/current |
| Environment | Your site variables + PORT=<app port>, HOST=127.0.0.1, NODE_ENV=production (unless you set it), PATH=/usr/local/bin:/usr/bin:/bin, plus FALAK_SITE, FALAK_SITE_ID, FALAK_SERVER_ID, FALAK_RELEASE_ID, FALAK_DEPLOYMENT_ID |
| App port | Allocated per server from 3000–3999, shown as app_port on the site |
| User | The site user (falak by default) |
| Health check | GET / expecting 200 (change under Settings → Deploy) |
| Deploy script | $FALAK_FETCH → $FALAK_ACTIVATE → $FALAK_RESTART_PROCS |
| On deploy | The web process restarts in the new release |
Framework notes
Section titled “Framework notes”- Preset variables:
NODE_ENV=production,NEXT_TELEMETRY_DISABLED=1. - Make sure
startisnext start(it readsPORTautomatically). - Build-time public variables must start with
NEXT_PUBLIC_to reach the build. See Builds. - APM: add
instrumentation.tswith@falak/apm-node/next. See APM for Node.
- Preset variables:
NODE_ENV=production,NITRO_PRESET=node-server. startshould run the Nitro server:node .output/server/index.mjs.- Public runtime config variables start with
NUXT_PUBLIC_.
- Use the Generic Node preset.
- Listen on
PORT. Bind toHOST(127.0.0.1) so the app is only reachable through Caddy.
- Use the Node adapter (
@astrojs/node,@sveltejs/adapter-node, Remix’s Node server) and astartscript that runs the built server. - Without an SSR adapter, Astro and Vite apps are static sites.
Workers and cron
Section titled “Workers and cron”Add background processes (node worker.js, BullMQ consumers) as daemons and scheduled scripts as cron jobs in the Processes tab. See Processes.
Node.js versions
Section titled “Node.js versions”Servers offer Node 20 (20.19.5), 22 (22.20.0, default) and 24 (24.9.0). The builder reads your project’s Node version. Pick the site’s Node version in Settings → Build. Sites can select 18, 20, 22 or 24; make sure the server has that version installed.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause and fix |
|---|---|
Health check fails, logs say Missing script: "start" |
Add a start script to package.json. |
| 502 from the domain | The app does not listen on PORT, or crashed. Check the site’s Logs tab. |
EADDRINUSE |
You hard-coded a port. Use process.env.PORT. |
| Build fails with a lockfile error | Commit your lockfile, or override the install with FALAK_INSTALL_COMMAND. |
| Environment variable undefined in the browser bundle | Build-time variables need a public prefix (NEXT_PUBLIC_, VITE_, …) or must be exposed to the deploy script. |