Skip to content

Deploying

Deploy a Node.js app (Express, Fastify, NestJS)

How DployHub detects and deploys Node.js apps: package manager, build and start commands, port detection and the settings you can override.

Updated 3 min read

Any repository with a package.json at its root folder is treated as a Node.js project. DployHub picks the package manager, build command, start command and port for you, builds on node:20-alpine with NODE_ENV=production, and runs the result with zero-downtime releases. This guide explains each detection rule so you know exactly what will happen.

Package manager and install

We read your lockfile to decide how to install dependencies:

  • pnpm-lock.yaml means pnpm.
  • yarn.lock means yarn.
  • Otherwise npm: npm ci || npm install when a package-lock.json exists, else npm install.

If your package.json has a build script, we run it as the build command (npm run build, yarn build or pnpm build).

Start command

We look for a way to start your server in this order:

  1. A start script: npm start (or yarn start / pnpm start).
  2. NestJS with a start:prod script: npm run start:prod.
  3. Next.js: npx next start. Nuxt: node .output/server/index.mjs.
  4. Otherwise node with the main field, or the first of server.js, index.js, app.js, src/index.js, src/server.js that exists.

If none of these is found the build stops with: We could not tell how to start your app. Add a "start" script to package.json, or set a start command. The fix is a one-line start script:

json
{
  "name": "shop-api",
  "scripts": {
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

Port detection

We check the start script for PORT=4000, --port 4000 or -p 4000, then the entry file for a literal such as process.env.PORT || 4000 or .listen(4000). If nothing is found we use 3000. We always set the PORT environment variable, so the safest pattern is:

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

app.get('/', (req, res) => res.send('ok'));

const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => console.log('listening on ' + port));

Front-end only projects

If the project has a build script but no server framework (Express, Fastify, Koa, Hapi, NestJS, Next.js, Nuxt, Remix, SvelteKit, Astro node adapter or Hono), we treat it as a static front-end and serve the build output. React, Vue, Angular, Vite, Gatsby and Astro sites are covered in Deploy a static site.

Overriding detection

Pick Node.js under How to build it to skip auto-detection, and set any field yourself: build command, start command, port, root folder and health check path. All of these can also be changed later in the app Settings. Store secrets as environment variables, never in the repository.

There is also a quick framework guide at /deploy/nodejs and /deploy/express. If a build fails in a way the logs do not explain, raise a ticket.

Frequently asked questions

Which Node.js version is used?

Detected Node.js apps build and run on node:20-alpine. If you need another version, use your own Dockerfile.

Do you support pnpm and yarn?

Yes. A pnpm-lock.yaml selects pnpm and a yarn.lock selects yarn; otherwise npm is used.

What port should my app listen on?

Read process.env.PORT and listen on 0.0.0.0. We always set PORT to the port configured for the app.