Node.js, Next.js and Nuxt applications.
How Node.js projects are detected and started: Node version, package manager, Next.js and Nuxt (server or static), SvelteKit, Astro, Express and friends, the PORT variable and Prisma migrations.
A repository with a package.json is a Node.js project. We pick the framework, the package manager and the Node version, build it and start it — you only push.
Node version and package manager
- Node.js — taken from
engines.nodeinpackage.jsonor from.nvmrc: the newest of 24, 22, 20, 18 or 16 that fits. Without either, Node.js 22. - Package manager — by the lock file:
pnpm-lock.yaml→ pnpm,yarn.lock→ yarn, otherwise npm (npm ciwhen there is apackage-lock.json). - Build — the
buildscript, whenpackage.jsonhas one.
Frameworks
| Framework | How it runs |
|---|---|
| Next.js | as a server (next start) — server rendering, API routes and middleware work as usual |
Next.js with output: 'export' | as a static site from out |
| Nuxt | as a server (.output/server/index.mjs) |
Nuxt with ssr: false and a generate script | as a static site from .output/public |
| SvelteKit | as a server with adapter-node; with adapter-static, as a static site |
| Astro | as a static site; with @astrojs/node, as a server |
| NestJS | dist/main.js after the build |
| Express, Fastify, Koa, Hono and other servers | the file in scripts.start (node server.js), else main, else server.js, app.js, index.js or main.js |
Front-end-only projects — Vite, Create React App, Angular, Vue CLI and others — are served as static sites; see Static sites.
Listen on PORT
A server must listen on the port in the PORT variable, on all interfaces:
const port = process.env.PORT || 3000
app.listen(port, '0.0.0.0')Next.js and Nuxt do this by themselves. If your application listens on a fixed port, it will not receive visitors — the deploy then stops at the start check and the previous version keeps running.
Build-time values
Variables from the Variables tab reach the running application, not the build. Values that the build writes into the client code — such as NEXT_PUBLIC_… in Next.js or VITE_… — are read from your repository, for example from a committed .env.production file. Server-side code reads the Variables tab as usual.
Your own start command
If the detected start isn't what you want, set Settings → Build settings → Start command, e.g. node dist/server.js or npm run start:prod. Install and build commands can be changed there too.
Databases and Prisma
Add PostgreSQL or MySQL to the project and read DATABASE_URL — it is set for you. With Prisma in your dependencies, the recommended release command is npx prisma migrate deploy: it runs on every deploy before the new version receives visitors. See Deploys.
For queues with BullMQ, add Valkey and use REDIS_URL. Run the queue worker as a background worker — on the Processes tab, or as a separate service with its own resources. See Services of a project.
Files that outlive a deploy
Each deploy starts from a fresh copy of your repository. Files your application writes to /data are kept between deploys and backed up daily; anything written elsewhere is gone after the next deploy. For uploads and media, object storage is usually the better choice.
Monorepos
For a repository with several projects, set the Project folder when you create the application (e.g. apps/web). Another folder of the same repository can run as a separate web service — see Services of a project.