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 project | What 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.PORT | The runtime injects `PORT`. Read it instead of hardcoding a port. |
0.0.0.0 | Listen on all interfaces so the router can reach the process. |
lannzo.json → runtimeFiles | Optional. 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 order | What Lannzo expects |
|---|---|
lannzo project config --start-command | The project configuration, which wins over everything in the repository. |
lannzo.json → startCommand | `lannzo.json` in the built directory. |
package.json → scripts.start | Used as-is, so it has to be `node <file>` rather than a wrapper script. |
package.json → main | The `main` field, when there is no start script. |
server.js · index.js · app.js | Conventional 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 --prodTo 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 --gitEnvironment 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.jsOperate 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 previewWhen 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>.