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:
nimbus deploy
Before you do, check four things:
npm startstarts your server, or add aProcfilewith aweb:line. See 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.lockorpnpm-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.
Node version#
Without engines in package.json, the build uses its current default Node version, which changes over time. Pin it for reproducible builds:
"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.
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:
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.
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.
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.
Also available as Markdown.