# Node.js

A Node.js app deploys from its repository with no `Dockerfile`. Nimbus Land reads your `package.json`, installs your dependencies, runs your build and starts your app.

## Quick start

A stock Express app deploys as is: `npm start` is the web process, and Express already listens on `PORT`.

In the console, create an app from your repository with the deploy wizard. From the CLI, run this in the project directory:

```sh
nimbus deploy
```

Before you do, check four things:

- **`npm start` starts your server**, or add a `Procfile` with a `web:` line. See [what every app needs](apps.md#what-every-app-needs).
- **Your server listens on `PORT`.** A hard-coded port never receives traffic.
- **Commit a lockfile** (`package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` or `pnpm-lock.yaml`).
- **Pin the Node version** with `engines`, as shown below.

To see what Nimbus Land would run before you deploy, use `nimbus detect`. See [the deploy plan](apps.md#the-deploy-plan).

## Node version

Without `engines` in `package.json`, the build uses its current default Node version, which changes over time. Pin it for reproducible builds:

```json
"engines": { "node": "24.x" }
```

## Lockfiles

Nimbus Land installs from `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` or `pnpm-lock.yaml`. If you commit none, the build generates a `package-lock.json` with the newest versions `package.json` allows, and the build log says `Nimbus: no lockfile committed, generating package-lock.json for this build`. Commit your own lockfile for reproducible builds.

## NODE_ENV and devDependencies

`NODE_ENV` is never passed to a build. With `NODE_ENV=production`, npm, Yarn and pnpm skip `devDependencies`, so `tsc`, `vite build` or `next build` would fail with `not found`. Instead, Nimbus Land installs everything, runs your build, removes `devDependencies` from the image and sets `NODE_ENV=production` for your app. Your own `NODE_ENV` still applies at run time.

This means a package that your app needs while running must be under `dependencies`, not `devDependencies`. For the rest of the build-time and run-time rules, see [environment variables](apps.md#environment-variables).

## Next.js

A stock `create-next-app` project deploys as is: `next build` runs with `devDependencies` installed, and `npm start` serves on `PORT`. Next.js builds run with `NEXT_TELEMETRY_DISABLED=1` unless you set it.

`NEXT_PUBLIC_*` variables are inlined into the browser bundle by `next build`, so they must exist at build time. Store them as plain variables on the app: a secret never reaches the build, and anything `NEXT_PUBLIC_` is public anyway. Changing one takes effect on the next build, not on the running release.

## Database TLS

Attaching a managed Postgres database sets `DATABASE_URL` and `DATABASE_CA_CERT`. By default, `pg` and Prisma connect without verifying the database's certificate, and that works as is.

To verify it, give node-postgres the CA:

```js
const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: { ca: process.env.DATABASE_CA_CERT },
});
```

Don't add `?sslmode=require` to a node-postgres URL: it then verifies against the system's trust store, which doesn't include the database's authority, and fails.

## Troubleshooting

For problems that aren't specific to Node, such as an app that never answers, see [Apps troubleshooting](apps.md#troubleshooting).

### `Error: Cannot find module 'express'`

The package isn't in the image: your lockfile is out of date with `package.json`, the package is only in `devDependencies` (removed after the build), or it isn't in `package.json` at all. Add it under `dependencies`, run `npm install`, commit `package-lock.json` and deploy again.

### `self-signed certificate in certificate chain`

A Node driver set to verify the database's certificate doesn't know its authority. Pass `DATABASE_CA_CERT` as shown under [Database TLS](#database-tls).

### The build ran out of memory

The failure reason names the limit. Set `NODE_OPTIONS=--max-old-space-size=<MiB>` on the app (it reaches the build as a plain variable) or trim the build.
