Skip to content
Docs

Node.js

Deploy Next.js, Nuxt, Express or any Node.js app. We detect your framework and package manager, build it, and start it on port 8080.

Updated 27 Oct 20264 min read

A Node.js app deploys from its package.json. We choose Node.js 22 or 24, install your packages with the manager your lock file names, run your build script if there is one, and start the app. Your app must listen on the port in the PORT variable, which is always 8080.

Versions

VersionNotes
Node.js 24What new apps get when the code doesn't ask
Node.js 22Still supported

We read the version your code asks for from .nvmrc, .node-version or .tool-versions first, then from the engines field of package.json, and use our default, Node.js 24, when it fits, otherwise the newest version that does. >=20 builds with Node.js 24; ^22 or 22 builds with 22. If the code asks for one we no longer offer, like 20, we build with the nearest newer one, 22, and the plan says why. To pin one, choose it in the app's Set up and run settings, or set "version": "22" in tanzahost.json.

What we detect

Your code hasWe use
packageManager in package.json, like yarn@4.5.1That exact manager and version
pnpm-lock.yamlpnpm
yarn.lockYarn
package-lock.jsonnpm, with npm ci
No lock filenpm, with npm install, and the plan suggests committing one

Development packages are installed too, because builds need them (Vite, Tailwind CSS, TypeScript). NODE_ENV is production for the build and the app. A build of your assets gets the build's memory, so Vite and Next.js don't run out.

We recognise Next.js, Nuxt, Remix, SvelteKit, Astro, NestJS, Express, Fastify, Koa and Hono, workspaces (pnpm-workspace.yaml, turbo.json, nx.json, with the plan saying which folder is the app), and Prisma, Drizzle and Knex. Then we start the app this way, first match wins:

  1. A web: line in a Procfile.

  2. A start script in package.json: npm run start (or pnpm's or Yarn's).

  3. Next.js without one: its standalone server when next.config sets output: 'standalone', otherwise next start -p ${PORT}. With output: 'export', it's served as a static site.

  4. Nuxt: its built server, .output/server/index.mjs, with Node.js.

  5. NestJS: node dist/main.

  6. The main file of package.json, or else the first of server.js, server.mjs, index.js, app.js or main.js, with Node.js.

A project with a build script and no way to start, like a React or Vue app made with Vite, is served as a static site.

Databases, caches and email, made for you

The plan reads which database your code uses (pg, mysql2, mongoose, Prisma's or Drizzle's provider) and makes it before your first deploy, with its price first: PostgreSQL and MySQL set DATABASE_URL, MongoDB sets MONGODB_URI. A Redis client (ioredis, redis, BullMQ) gets a cache. Prisma's migrations run before each version goes live (prisma migrate deploy). NEXTAUTH_SECRET, AUTH_SECRET, JWT_SECRET and SESSION_SECRET are made for you when your example file leaves them empty, and NEXTAUTH_URL is filled with your app's address. Keys only you have, like Stripe's, are listed as "Needs your key" and never invented.

Listen on PORT

Visitors reach your app's web process on port 8080, given to it as PORT. Listen on every address, not only localhost:

js
const express = require("express");
const app = express();

app.get("/", (req, res) => res.send("Hello from duka!"));

app.listen(process.env.PORT || 8080, "0.0.0.0");

A new version gets visitors only once it answers its health address ("/" unless you choose another) with a success, within 2 minutes. If your code listens on a fixed port instead, like app.listen(3000), the first deploy finds the port it opened, serves your app from it, and tells you. See Deploying.

Example: Asha's shop API

Asha adds a second app, api, to her project duka, from a GitHub repository with Express, a package-lock.json, and an .nvmrc file that says 22. Its package.json has:

json
{
  "scripts": {
    "build": "tsc --noEmit",
    "start": "tsx src/server.ts"
  },
  "dependencies": {
    "express": "^5.1.0",
    "tsx": "^4.20.0"
  }
}

We find Express on Node.js 22, run npm ci --include=dev, then npm run build (her type check), then start it with npm run start. It's live on its own free address, like api-duka-k2m9.tanzahost.co. Her shop's database is attached to it too, so DATABASE_URL is already in its variables.

Build variables

Next.js and Vite put some variables into the built files (like NEXT_PUBLIC_… and VITE_…), so builds get your app's variables too. After changing one of those, deploy again to rebuild.

Change what we found

On the app's page, Set up and run shows the language, version, folder, and the install, build and start commands we worked out. Change any of them; an empty field uses what we found. For an app in a folder of a larger repository (a monorepo), set Folder, like apps/api.

Workers

A queue consumer or any long-running script runs as a worker beside the web process, with its own command, like npm run worker. See Workers.