Guides
Node.js — Next.js, Express and more
How Meghly recognises, builds and runs a Next.js, Express or any other Node.js app — with workers and migrations.
What runs
- Node.js 24 and 22.
- Package managers: npm, yarn or pnpm — told apart by the lock file (
package-lock.json,yarn.lock,pnpm-lock.yaml) orpackageManagerinpackage.json. - Frameworks: Next.js, Express, and any server with a
startscript (Fastify, NestJS, Koa, Hono …). - A front-end only (React, Vue, Vite, Angular …) runs as a static site — see Static sites.
Node version
Meghly takes the version in this order: .nvmrc → .node-version → engines.node in package.json. With none, the default version. To be sure, set one:
{
"engines": { "node": "22" }
}What Meghly runs
| When it finds | Web process |
|---|---|
a next dependency | npm run build, then next start -p 8080 |
a start script | npm start (or the yarn/pnpm equivalent) |
no start, but main or server.js, index.js, app.js, main.js | node <that file> |
A build script in package.json runs during the build. For your own server, listen on PORT and on 0.0.0.0:
const express = require("express");
const app = express();
app.get("/", (req, res) => res.send("Hello from Meghly"));
app.listen(process.env.PORT || 8080, "0.0.0.0");Workers
A script called worker, queue or jobs in package.json runs as a separate worker process — a BullMQ or queue consumer, for example:
{
"scripts": {
"start": "node server.js",
"worker": "node jobs/worker.js"
}
}For more control, write a Procfile.
Migrations
They run in the release before each deploy (with the migration login):
- a
migrate,db:migrateorprisma:migratescript, if there is one; - with Prisma,
prisma migrate deploy; - for anything else (Knex, TypeORM, Drizzle, Sequelize), set your own command in the app's General → Release command, such as
npx knex migrate:latest.
Databases
A linked database brings DATABASE_URL — Prisma, Drizzle and Knex all read it directly:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}A linked Redis brings REDIS_URL, RabbitMQ RABBITMQ_URL. See Databases.
Next.js tips
- Variables starting with
NEXT_PUBLIC_are baked into the code at build time. Changing one needs a new deploy, not just a restart. - The
next/imagecache and anything else written at run time goes to/tmpor a volume; writing to.next/cachewhile running is not reliable. - WebSockets (socket.io) work on the app's HTTPS address with no extra setting.
When something goes wrong
| What you see | Cause and fix |
|---|---|
| Detect: "No start script, main file or server.js" | Add a start script to package.json. |
| The deploy stops at the health check | Check the app listens on process.env.PORT and 0.0.0.0. |
EROFS: read-only file system | You are writing into the app's folder — use /tmp or a volume. |
| The wrong Node version | Set .nvmrc or engines.node. |