Guías de frameworksNode.js (Express)

Desplegar una app de Node.js (Express)

Para alojar una app de Node.js en Lizard (lizard.build), despliega una carpeta con un package.json. lizardpack elige el gestor de paquetes según tu archivo de bloqueo, instala las dependencias, ejecuta el script build si existe e inicia la app con el script start en el puerto 3000. Usa Node.js 22 salvo que .nvmrc o engines.node indiquen otra versión principal. Lizard pasa el puerto en PORT; escucha en él.

Estado de las pruebas: el ejemplo de Express de abajo funcionó localmente con Express 5.3.0, y la ruta de base de datos, con pg 8.23.1 contra PostgreSQL 14. Revisamos su plan de compilación con lizardpack, el planificador de compilación que ejecuta Lizard. Todavía no lo hemos desplegado de principio a fin con esta guía.

Antes de empezar

  • Node.js y npm en tu equipo para crear el archivo de bloqueo y probar localmente.
  • Lizard CLI, con la sesión iniciada mediante lizard login, en Pro o en la prueba de Pro de 7 días (se requiere tarjeta). Consulta los precios.

Las apps de Next.js, Nuxt, Astro, SvelteKit y Vite tienen sus propias guías: consulta las guías de frameworks.

Una app mínima de Express

package.json:

{
  "name": "express-app",
  "private": true,
  "type": "module",
  "scripts": {
    "start": "node server.js"
  },
  "engines": {
    "node": "22.x"
  },
  "dependencies": {
    "express": "^5.1.0"
  }
}

server.js:

import express from "express";
 
const app = express();
const port = Number(process.env.PORT) || 3000;
 
app.get("/", (req, res) => {
  res.send("Hello from Express on Lizard");
});
 
app.get("/healthz", (req, res) => {
  res.json({ status: "ok" });
});
 
app.listen(port, "0.0.0.0", () => {
  console.log(`listening on ${port}`);
});

Ejecuta npm install para crear package-lock.json, haz commit de ambos archivos y añade node_modules y .env a .gitignore. Pruébala localmente:

npm start
curl http://localhost:3000/healthz

Qué hace lizardpack con una app de Node.js

PasoQué ocurre
Gestor de paquetesbun.lock o bun.lockb: Bun. pnpm-lock.yaml: pnpm. yarn.lock: Yarn. package-lock.json: npm ci. Sin archivo de bloqueo: npm install.
Versión de Node.js.nvmrc, luego .node-version, luego .tool-versions, luego engines.node. Solo la versión principal, sobre node:<major>-slim. Predeterminada: 22.
CompilaciónEl script build, si package.json lo tiene, en una etapa aparte que incluye tus devDependencies
InicioEl script start; si no, node <main>; si no, el primero de server.js, index.js, app.js, main.js, dist/index.js
EjecuciónNODE_ENV=production, puerto 3000

Sin un script build, la imagen define NODE_ENV=production antes de instalar los paquetes, así que las devDependencies quedan fuera. Un script de inicio que llama a nodemon, tsx o ts-node desde las devDependencies falla entonces. Con TypeScript, compila en build e inicia la salida:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Los archivos de versión y sus casos límite están en versiones del entorno de ejecución. Deja vacíos los comandos de compilación e inicio del servicio: si defines cualquiera de los dos, Lizard escribe su propio Dockerfile sobre node:22-alpine e ignora tus archivos de versión. Consulta el pipeline de compilación.

Desplegar

Desde la raíz de la app:

lizard init --name node-app
lizard add --service web
lizard up --service web --port 3000

lizard up sube la carpeta, la compila en Lizard e imprime la URL. Dentro de un repositorio git omite lo que aparece en .gitignore; fuera de git omite node_modules, pero sube los archivos .env. Consulta desplegar desde código local.

Para usar git push to deploy, sube el repositorio a GitHub y conéctalo con lizard add -r your-org/your-app -n web. Consulta desplegar desde GitHub.

Configurar variables

lizard secrets set SESSION_SECRET="$(openssl rand -hex 32)" --service web

Lee los valores con process.env.SESSION_SECRET. Un cambio de variable reinicia el servicio sin volver a compilar. Consulta variables y secretos.

Añadir Managed Postgres

lizard add postgres
lizard secrets set DATABASE_URL='${{postgres.DATABASE_PRIVATE_URL}}' --service web
npm install pg

Las comillas simples evitan que tu shell interprete ${{…}}; Lizard resuelve la referencia al desplegar y la convierte en la dirección de la base de datos en la red privada del proyecto. Añade un pool y una ruta a server.js:

import pg from "pg";
 
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
 
app.get("/db", async (req, res) => {
  const { rows } = await pool.query("SELECT now() AS now");
  res.json(rows[0]);
});

Express 5 pasa una promesa rechazada de una ruta a su manejador de errores, así que una consulta fallida devuelve HTTP 500 en lugar de detener el proceso. Ejecuta las migraciones desde tu equipo con la URL pública de la base de datos:

lizard run --service postgres -- npm run migrate

Para una caché o una cola de trabajos, añade Managed Redis del mismo modo: lizard add redis y después REDIS_URL='${{redis.REDIS_PRIVATE_URL}}'.

Comprobar que funciona

lizard logs --build --service web
lizard logs --service web --tail 100
lizard ps

El log de ejecución muestra listening on 3000. Solicita /healthz y /db en la URL que imprimió lizard up.

Problemas comunes

SíntomaSolución
npm ci falla porque el archivo de bloqueo no está sincronizadoEjecuta npm install localmente y haz commit de package-lock.json.
nodemon: not found o tsx: not foundEsas herramientas son devDependencies y no se instalan para el inicio. Añade un paso build o mueve la herramienta a dependencies.
El despliegue nunca alcanza el estado healthyEscucha en process.env.PORT. Un puerto fijo como 5000 no coincide con el puerto del servicio. Consulta el servicio nunca alcanza el estado healthy.
Versión de Node.js incorrectaPon la versión principal en .nvmrc, por ejemplo 24, y vuelve a desplegar.
Cannot use import statement outside a moduleAñade "type": "module" a package.json o usa require.

Un proceso de Node.js que no sirve HTTP, como un consumidor de cola o un bot de Discord, se ejecuta como worker en segundo plano.

Relacionado

Actualizado