Node.js

Host a Node.js app in Germany.

Pin Node 22 in package.json, listen on process.env.PORT and add a run-zero.yaml. The buildpack installs everything and runs npm start on servers in Nuremberg.

Needs the Developer plan, the free plan only covers websites. Pricing · Check the limits first

  • Express tested
  • npm start as the start command
  • HTTPS from the first deploy
claude · run-zero-examples/node-express

> Deploy the node-express folder to run.zero.

runzero_create_appdoneexample-node-express

runzero_push_filesdoneone commit

runzero_deploydoneservices created

runzero_wait_for_builddonelive

live at https://web-example-node-express-2311463c.run-zero.de

The session that created the live demo, with the real MCP tools.
How it works

Live in four steps.

Tested with the example that runs live.

  1. 01

    Pin Node 22

    Add "engines": {"node": "22.x"} to package.json. Node 23 and newer crash on the build stack, and loose ranges like >=18 resolve to them.

  2. 02

    Listen on $PORT

    The server reads its port from process.env.PORT. A fixed port like 3000 is not reachable from outside.

  3. 03

    Add run-zero.yaml

    One service is enough. Its name becomes part of the address, here web.

    run-zero.yaml
    version: "1"services:  web:    port: 8080
  4. 04

    Create an account and deploy

    Create an account, connect your agent with this command, then sign in from Claude Code with /mcp and Authenticate.

    • Then tell your agent: deploy this repo to run.zero.
    Without an agent

    Create the app in the dashboard and connect your GitHub repo. Every push rebuilds.

    Connect Claude Code
    claude mcp add --transport http \  -s user run-zero \  https://api.run-zero.de/mcp \  --client-id runzero-cli \  --callback-port 53761

After 1 to 3 minutes the app is live at https://web-<app>.run-zero.de. Check a route of your app, in the example /api/health. If the build is red, runzero_get_build_logs tells you why.

Files

Two files plus the config.

Exactly as they sit in the example that runs live.

Listens on process.env.PORT, 8080 when no port is set.

Example on GitHub(opens in a new tab)
node-express/server.js
// Minimal Express app for run.zero. The platform sets PORT, default 8080.const express = require('express');const app = express();const port = process.env.PORT || 8080;app.get('/', (req, res) => {  res.type('html').send(`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Express on run.zero</title></head><body style="font-family:system-ui,sans-serif;max-width:640px;margin:64px auto;padding:0 24px"><h1>Express on run.zero</h1><p>This Node.js app was built by a Paketo buildpack and listens on port ${port}.</p><p><a href="/api/health">/api/health</a></p></body></html>`);});app.get('/api/health', (req, res) => {  res.json({ status: 'ok', runtime: `node ${process.version}`, platform: 'run.zero' });});app.listen(port, () => console.log(`listening on ${port}`));

engines pins the version, start runs the server.

Example on GitHub(opens in a new tab)
node-express/package.json
{  "name": "run-zero-example-node-express",  "version": "1.0.0",  "private": true,  "engines": { "node": "22.x" },  "scripts": { "start": "node server.js" },  "dependencies": { "express": "^4.21.2" }}
Limits

What does not work today.

So the first build goes through.

  • Needs the Developer plan

    Free has no server apps and no Postgres, a deploy stops with an error.

    See pricing
  • Build tools in dependencies

    The buildpack prunes devDependencies. Whatever the build needs belongs in dependencies.

  • No build in the start script

    npm run build already runs at image build time. At runtime the app directory is read-only.

  • Files need a volume

    Without volumes:, uploads are gone after a restart. Volumes start at the Developer plan, and we tested them with the PocketBase image.

Operations

What you stop doing yourself.

Builds, HTTPS, the database and backups run on the platform.

  • Data stays in Germany

    Servers and backups at Hetzner in Nuremberg. With a data processing agreement.

  • HTTPS by default

    Every service gets an address on run-zero.de, custom domains a Let’s Encrypt certificate.

  • Postgres as an addon

    One entry in run-zero.yaml, DATABASE_URL arrives as an environment variable.

  • No lock-in

    Your code stays in your repo, the database is a dump you can download.

Questions.

About Node.js.

Do I need a Procfile?

Not if package.json has a start script. The buildpack runs npm start. You only need a Procfile for a different start command.

Which Node version runs?

The one you pin in engines. The live demo reports the exact version at /api/health.

How do I attach a database?

With a Postgres addon in run-zero.yaml. With node-postgres, pass ssl: { rejectUnauthorized: false } and drop sslmode from DATABASE_URL. The compose example shows both.

Does this work with NestJS, Fastify or Hono?

The buildpack detects any app with a package.json. We only tested Express here. What matters is the version, $PORT and a start script.

More guides

All guides

Your code. Live on run.zero.

One website is free, no credit card. Apps with a server, a database and a custom domain come with the Developer plan.