Language Frankfurt, Germany

Deploy Node.js on Nodion

Connect a repository with a package.json and Nodion builds it with its Node.js buildpack: it installs your dependencies from the lockfile, runs your build script and starts the server with your start script. Express, Fastify, Hono and other Node.js servers work this way, and so do Bun projects. The app runs in Frankfurt, next to a managed PostgreSQL database if you need one.

Deploy to Nodion ›

from 1 EUR / month

Up to 15 € credit when signing up

Detected by
package.json without a static frontend framework
Start
start script, else node server.js, index.js or app.js
Node.js
22, 24 (default), 26
Region
EU Central (Frankfurt)

Deploy Node.js step by step

  1. Listen on PORT Nodion sets PORT for the web process and sends traffic there. Read it and bind to 0.0.0.0. Fastify listens on localhost by default, so pass host: '0.0.0.0' to listen. server.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");
  2. Commit a lockfile and a start script Commit package-lock.json, yarn.lock, pnpm-lock.yaml or bun.lock; the build fails without one. Nodion runs the start script directly, so npm hooks such as prestart do not run. Without a start script, known frameworks such as Nuxt get their own default; everything else starts with node server.js, index.js or app.js, and finally node .. Dev dependencies are removed after the build, so tools you need at runtime, such as tsx or a migration CLI, belong in dependencies. package.json
    "scripts": {
      "start": "node server.js"
    }
  3. TypeScript: keep a JavaScript entry file If package.json has a build script and none of server.js, app.js, index.js, src/server.js, src/index.js or src/app.js exists, Nodion treats the repository as a static site and does not start your server. A TypeScript server that tsc compiles into dist/ looks exactly like that. Add an index.js next to package.json that loads the compiled server (the snippet needs "type": "module"; in CommonJS write require("./dist/server.js")), and point the start script at the compiled file, for example node dist/server.js, not at a dev tool. index.js
    import "./dist/server.js";
  4. Create the app and set variables In the dashboard, create an application from your GitHub, GitLab, Bitbucket or Gitea repository, pick the branch and the region EU Central. Variables your build script reads need the Build flag on the Environment tab; all others only exist at runtime. Mark API keys as secret.
  5. Attach PostgreSQL and run migrations Create a PostgreSQL database in the same region and attach it on the Environment tab: from the next deploy on, your app reads DATABASE_URL. A release: line in a Procfile runs once per build, after the build and before the new version starts; if it fails, the running version stays live. Procfile
    release: npm run migrate
  6. Push to deploy Every push to the branch builds a new release. Traffic moves to it once / answers with a 2xx or 3xx status. If your API answers 404 on /, add a route such as /health and set it as the health check path in the app settings.

Good to know

  • Vite in package.json means a static siteWith vite in dependencies or devDependencies, Nodion builds the repository as a static site and ships only the build output, even if a server.js exists. The same goes for Angular, Gatsby, Create React App and Eleventy. For a Node.js server that also builds a Vite frontend, use a Dockerfile.
  • BunWith a bun.lock, Nodion installs your dependencies and runs the build with Bun. The app still starts through the start script, so the script has to call Bun, for example "start": "bun run index.ts"; without one, Nodion starts the app with node. The entry file rule above applies to Bun projects too.
  • Queue workersPut web: node server.js and worker: node worker.js in a Procfile; without a web: line, the first Procfile entry other than release: becomes the default command. Then add a process named worker without a port on the Processes tab. Valkey in the same region gives your queue a REDIS_URL.

What Nodion runs for you

  • Deploys without downtime Push to your branch and Nodion builds a new release. Traffic switches once the new instances answer their health check; a failed release leaves the running one in place. Apps with a local volume restart instead, because the disk belongs to one instance.
  • Databases next to the app Managed PostgreSQL, pgvector, MySQL, Valkey and ClickHouse in the same region. Attached databases arrive as DATABASE_URL, REDIS_URL or CLICKHOUSE_URL.
  • Previews per pull request Turn on previews and pull requests from your repository get their own app with its own URL and fresh, empty databases, created automatically or by hand. Forks and bot pull requests are skipped.
  • Workers, cron jobs and scaling Run workers as extra processes of the same app, schedule jobs on the Cron tab, and scale every process to up to 16 instances.
  • Release step With buildpacks, a Procfile release: line runs with every new build. Dockerfile apps, and redeploys or rollbacks to an earlier image, use a release command set on the app itself, which also takes precedence over the Procfile line. On static sites a release step runs in an image that holds only the built files.
  • Logs and metrics Build, release and runtime logs plus CPU, memory, disk and network metrics for every instance in the dashboard.
  • Domains and HTTPS A default hostname with HTTPS from the first deploy; your own domains get certificates automatically.

Further reading

Node.js on Nodion: questions and answers

Why is my Node.js server built as a static site?

Nodion found a build script but none of the entry files server.js, app.js or index.js (also checked under src/), or a static frontend framework such as Vite in package.json. Add an index.js next to package.json that loads your compiled server; with Vite in the same package.json, use a Dockerfile.

Which Node.js version does my app get?

Node.js 24, unless you choose one. Nodion reads .node-version, .nvmrc and engines.node, in that order. A range resolves to the newest matching release, so "node": ">=20" gets Node.js 26; write 24 into .nvmrc to stay on 24.

Can I use pnpm, Yarn or Bun?

Yes. Nodion picks the package manager from the lockfile (pnpm-lock.yaml, yarn.lock, bun.lock or package-lock.json) and installs exactly the versions it lists. Bun projects also need a start script that calls bun.

Where does my Node.js app run?

In the EU Central region in Frankfurt, Germany. Build, registry, the app and its databases, volumes, buckets, logs and metrics stay in that region, and Nodion's API and control plane are hosted in Germany. Nodion GmbH is based in Stuttgart.

Can I use Node.js in line with the GDPR?

Nodion provides the basis for it: Nodion GmbH is based in Stuttgart, Germany, in the Frankfurt region the app, its databases and volumes run in Germany, and you conclude the data processing agreement (DPA) under Art. 28 GDPR electronically in the dashboard. Whether your setup complies also depends on how you configure and use the app.

How much does it cost to run Node.js on Nodion?

An app instance starts at 1 EUR per month. The setup in the cost box costs 3.50 EUR per month: App 2 EUR, PostgreSQL 1.50 EUR. Prices are net and billed per second, and you pick bigger sizes or more instances whenever you need them.

Can I use my own domain for my Node.js app?

Yes. Every app gets a default hostname with HTTPS. Add your own domain on the app's Domains tab; the TLS certificate is issued and renewed automatically.

Give your agent a cloud.

Earn up to 15 € in credit when signing up.

Continue with GitHub

or with email

Stay in the loop.

Product news, no spam. Unsubscribe anytime.