Deployment guides

Deploy a Node.js service

ExpressNode.js 22Any Node server

Lannzo runs plain Node processes in two ways. With express as a dependency it finds your entrypoint on its own; for anything else you name the start command, and it runs exactly that.

In both cases the runtime starts a single node <entrypoint> process and gives it a port.

What Lannzo expects

There is no process manager and no shell: the start command must be exactly node followed by one JavaScript file. Anything else — a shell pipeline, a package-manager script, several commands — is rejected during the build.

In your projectWhat Lannzo expects
node <entrypoint>The start command, resolved or configured. It must be exactly `node <file>`, and the file must exist after the build.
process.env.PORTThe runtime injects `PORT`. Read it instead of hardcoding a port.
0.0.0.0Listen on all interfaces so the router can reach the process.
lannzo.json → runtimeFilesOptional. Extra directories the runtime needs, when the entrypoint alone is not enough.

Express

An Express application needs nothing beyond reading the port from the environment:

// server.js
import express from "express";

const app = express();

app.get("/", (request, response) => {
  response.send("ok");
});

app.listen(process.env.PORT ?? 3000, "0.0.0.0");

Lannzo then looks for the entrypoint in a fixed order and takes the first one it finds. Declaring main or a start script removes any ambiguity:

{
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  }
}
Source, in orderWhat Lannzo expects
lannzo project config --start-commandThe project configuration, which wins over everything in the repository.
lannzo.json → startCommand`lannzo.json` in the built directory.
package.json → scripts.startUsed as-is, so it has to be `node <file>` rather than a wrapper script.
package.json → mainThe `main` field, when there is no start script.
server.js · index.js · app.jsConventional filenames, checked last, including `dist/server.js` and `dist/main.js`.

Any other Node server

Without Express, choose the generic node framework and give it the start command. Lannzo derives the entrypoint from that command, so it has to be the compiled file the process actually runs:

lannzo project config \
  --framework node \
  --build-command "npm run build" \
  --start-command "node dist/index.js"

The alternative is to keep the configuration in the repository. A lannzo.json at the root of the built directory declares the same fields, plus the extra files the runtime needs and a port when your server cannot read PORT:

{
  "version": 1,
  "framework": "node",
  "startCommand": "node dist/index.js",
  "entrypoint": "dist/index.js",
  "runtimeFiles": ["dist", "public"],
  "port": 3000
}

Deploy it

Link the directory once, and deploy. Preview and production are separate environments with separate variables and separate URLs.

lannzo link --project my-service
lannzo deploy
lannzo deploy --prod

To deploy from GitHub instead of your machine, connect the repository once. With --auto-deploy, every push to the production branch deploys on its own; without it, lannzo deploy --git deploys the head commit when you decide to.

lannzo repo connect --repository acme/my-service --branch main --auto-deploy
lannzo deploy --git

Environment variables

Mark credentials as secrets: they are written but never read back. For local development, env run injects the non-secret variables of an environment into a command without writing them to disk.

lannzo env set API_TOKEN --environment production --secret --target runtime
lannzo env run --environment preview -- node server.js

Operate the runtime

The runtime keeps one process alive and restarts it when it exits. You can also drive it explicitly, without creating a deployment:

lannzo runtime restart --environment production
lannzo runtime stop --environment preview

When a build fails

`NODE_START_COMMAND_INVALID`

The start command is not exactly node <file>. Commands such as npm start, node --watch server.js or two commands chained together are rejected: the runtime starts one process and passes it no shell.

`EXPRESS_ENTRYPOINT_MISSING` or `NODE_ENTRYPOINT_MISSING`

The entrypoint does not exist once the build has run. If it is generated, check that the build command produced it, and that any directory the process reads at runtime is listed in runtimeFiles.

Several frameworks detected

If the same package.json declares more than one supported framework, the build stops with FRAMEWORK_DETECTION_AMBIGUOUS instead of guessing. Pick one with lannzo project config --framework <framework>.