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 17 Oct 20263 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 a version file like .nvmrc first, then from the Node.js version in the engines field of package.json, and pick the newest version we offer that meets it. >=20 builds with Node.js 24; ^22 or 22 builds with 22. If the code asks for one we don't offer, we build with Node.js 24 and tell you so. To pin one, choose it in the app's Build and run settings, or set "version": "22" in tanzahost.json.

What we detect

Your code hasWe use
pnpm-lock.yamlpnpm
yarn.lockYarn
package-lock.jsonnpm, with npm ci
No lock filenpm, with npm install

Development packages are installed too, because builds need them (Vite, Tailwind CSS, TypeScript). A Bun lock file isn't used yet: the packages are installed with npm instead. NODE_ENV is production for the build and the app.

We recognise Next.js, Nuxt, Remix, SvelteKit, Astro, NestJS, Express, Fastify, Koa and Hono. Then we start the app this way, first match wins:

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

  2. Next.js without one: next start -p ${PORT}.

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

  4. 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.

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. 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, Build 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.