Busca en todas las páginas de la documentación
11 ejemplos para comenzar con scripts de Node.js -- 8 básicos y 3 intermedios.
Necesitas Node.js 22 LTS o más reciente. Verifica con node --version; instala vía nvm, fnm, o Volta si no lo tienes.
# Instala o cambia a la LTS actual con nvm
nvm install --lts
nvm use --lts
node --version # debería mostrar v22.x o superiorConvenciones para cada ejemplo siguiente:
package.json. Ejecuta npm init -y una vez para crear uno.import/export). Establece "type": "module" en package.json.tsx -- sin paso de compilación necesario durante el desarrollo.Un comando simple para confirmar tu toolchain antes de escribir cualquier script.
node --version # v22.15.0 o similar
npm --version # 10.x o similar
node -e "console.log('hello from node', process.version)"node -e "<code>" ejecuta un fragmento en línea -- perfecto para pruebas de humo sin crear un archivo.process.version reporta la versión de Node en ejecución para que detectes problemas de versión inmediatamente (p. ej., PATH antiguo recogiendo un binario antiguo).node falta, instala vía nvm (macOS/Linux) o fnm/Volta (multiplataforma) -- evita la instalación global de Homebrew en máquinas compartidas..nvmrc (o .node-version) para que cada colaborador ejecute el mismo runtime.Relacionado: Instalación de Node.js y npm -- nvm, fnm, Volta y el ciclo LTS
El archivo .js más pequeño y útil que puedes ejecutar con node.
// hello.js
const greeting = "Hello, Node.js!";
console.log(greeting);Ejecútalo:
node hello.js.js con código válido se ejecuta directamente bajo node -- sin bundler, sin configuración."type": "module" en package.json, los archivos .js se tratan como Módulos ES (import/export). Sin él, son CommonJS (require/module.exports).node --watch hello.js durante el desarrollo para volver a ejecutar al guardar (Node 18+ incorporado).process.argv contiene argumentos CLI; process.env contiene variables de entorno -- ambos siempre están disponibles.Relacionado: Ejecutar scripts JavaScript -- puntos de entrada, modo watch, líneas shebang | ESM vs CommonJS -- eligiendo el sistema de módulos
Salta el paso de compilación en desarrollo -- tsx ejecuta archivos .ts directamente.
npm install --save-dev tsx typescript @types/node// sum.ts
function sum(a: number, b: number): number {
return a + b;
}
console.log(sum(2, 3));Ejecútalo:
npx tsx sum.tstsx usa esbuild bajo el capó -- inicio rápido y el mismo comportamiento de stripping de tipos que en los builds de producción.tsx watch sum.ts para un bucle de desarrollo con recarga activa; usa npx tsc solo cuando quieras producir salida .js para despliegue.@types/node para que los módulos incorporados como fs, path y process estén tipados.node --experimental-strip-types sum.ts) -- un buen fallback cuando no puedes agregar tsx.Relacionado: Ejecutar scripts TypeScript -- tsx vs ts-node vs stripping nativo | ESLint para scripts de Node.js -- conectando lint a un proyecto de scripts TS
Ambas herramientas usan el mismo package.json; pnpm es más rápido y eficiente en disco.
# npm
npm install zod
npm install --save-dev tsx
# pnpm (habilita vía Corepack, no se necesita instalación global)
corepack enable
pnpm add zod
pnpm add -D tsxpackage.json es la fuente de verdad -- ambas herramientas la leen/escriben. Cambiar entre ellas es seguro si tu equipo acepta una a la vez.package-lock.json para npm, pnpm-lock.yaml para pnpm. Elimina el otro.corepack para fijar la versión exacta del gestor de paquetes en packageManager para que CI y laptops se mantengan alineados.Relacionado: pnpm vs npm -- workspaces, hoisting y comparación de rendimiento
Usa el sistema de módulos moderno -- importaciones estáticas, await de nivel superior, exportaciones con nombre.
// package.json
{
"type": "module"
}// math.ts
export function sum(a: number, b: number) {
return a + b;
}// app.ts
import { sum } from "./math.js";
console.log(sum(2, 3));"type": "module" en package.json para que los archivos .js/.ts sean ESM por defecto../math.js incluso cuando la fuente es math.ts.await está permitido en ESM: const data = await fetch(...) en la parte superior de un archivo funciona.Relacionado: ESM vs CommonJS -- reglas de interoperabilidad,
createRequirey cuándo CJS aún tiene sentido
Lee y escribe archivos de forma asincrónica -- la API recomendada desde Node 14.
fs/promises retorna Promises -- emparéjalo con top-level await para scripts limpios."utf8"); omítela solo si quieres un Buffer.node: (node:fs, node:path, node:url) -- inequívoco y funciona en ESM y CJS.createReadStream) o readline en lugar de almacenar todo el archivo en memoria.Relacionado: Scripts de utilidad -- E/S de archivos, rutas, globs y recetas de scripts
Usa parseArgs de node:util -- incorporado, tipado, sin dependencia extra.
// greet.ts
import { parseArgs } from "node:util";
const { values } = parseArgs({
options: {
name: { type: "string", short: "n", default: "world" },
shout: { type: "boolean", short: "s", default: false },
},
Ejecuta:
npx tsx greet.ts --name Ada --shout
# HELLO, ADA!parseArgs está incorporado en Node 18+ -- no hay necesidad de yargs o commander para la mayoría de scripts.short: "n" permite a los llamadores pasar -n Ada en lugar de --name Ada.values (flags analizados) y positionals (argumentos restantes) -- ambos completamente tipados desde el esquema.commander u oclif.Relacionado: Scripts de utilidad -- patrones CLI, prompts, códigos de salida
Pub/sub dentro de un único proceso -- la base para streams, servidores HTTP y eventos personalizados.
emit(name, ...args) llama a cada listener registrado con on(name, handler) en orden de registro.EventEmitter<T> (Node 22+) para obtener validación en tiempo de compilación de nombres de eventos y cargas útiles.off(name, handler) en procesos de larga ejecución -- los listeners olvidados pierden memoria.on agrega un listener persistente; once se dispara y se elimina a sí mismo -- elige el correcto para evitar handlers duplicados.Relacionado: Patrones de EventEmitter -- eventos tipados, fugas, iteración asincrónica
Cero dependencias -- sirve JSON desde el módulo http incorporado.
// server.ts
import { createServer } from "node:http";
const server = createServer((req, res) => {
if (req.url === "/health") {
res.writeHead(200, { "content-type": "application/json"
createServer retorna un EventEmitter -- también puedes escuchar "request", "connection", "close" directamente.res.writeHead antes de res.end; res.end cierra la conexión.process.on("SIGTERM", () => server.close(...)) para que los orquestadores de contenedores puedan cerrarte correctamente.Relacionado: Creación de servidores HTTP -- node:http, Express y Fastify lado a lado
API familiar, ecosistema enorme -- la opción predeterminada para la mayoría de servicios Node.js.
npm install express
npm install --save-dev @types/expressexpress.json() analiza cuerpos de solicitud application/json -- sin él, req.body es undefined.Request (Params, ResBody, ReqBody, Query) para que los handlers estén completamente tipados de extremo a extremo.zod o valibot dentro del handler para validar cuerpos en lugar de confiar en el cliente.Relacionado: Creación de servidores HTTP -- tradeoffs de Express vs Fastify vs node:http | ESLint para scripts de Node.js -- reglas recomendadas para código de servidor
ESLint moderno 9+ usa eslint.config.js (flat config) -- más limpio, rápido y consciente de tipos.
npm install --save-dev \
eslint typescript-eslint @eslint/js globals// eslint.config.js
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import globals from "globals";
export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
{
languageOptions: {
parserOptions: { projectService:
Ejecuta:
npx eslint .
npx eslint . --fix.eslintrc.* y .eslintignore -- mucho menos que aprender.recommendedTypeChecked activa reglas conscientes de tipos (necesita projectService: true), que detectan any inseguro y mal uso de promises.globals.node enseña a ESLint sobre process, Buffer, __dirname, etc., para que no desencadenen "no-undef".lint para que CI pueda fallar rápidamente en errores de estilo y tipo.Relacionado: ESLint para scripts de Node.js -- recomendaciones de reglas, configuración consciente de tipos, patrones de ignorancia | Configuración de ESLint (Linting & Formatting) -- referencia más amplia de ESLint
// read-config.js
import { readFile, writeFile } from "node:fs/promises";
const text = await readFile("config.json", "utf8");
const config = JSON.parse(text);
config.apiUrl = config.apiUrl.replace("http:", "https:");
await writeFile("config.json", JSON.stringify(config, null, 2));// read-config.ts
import { readFile, writeFile } from "node:fs/promises";
const text = await readFile("config.json", "utf8");
const config = JSON.parse(text) as { apiUrl: string };
config.apiUrl = config.apiUrl.replace("http:", "https:");
await writeFile("config.json", JSON.stringify(config, null, 2));// pubsub.js
import { EventEmitter } from "node:events";
const bus = new EventEmitter();
bus.on("login", (userId) => {
console.log(`User ${userId} logged in`);
});
bus.emit("login", "u_123");
bus.emit("login", "u_456");// pubsub.ts
import { EventEmitter } from "node:events";
interface Events {
login: [userId: string];
logout: [userId: string];
}
const bus = new EventEmitter<Events>();
bus.on("login", (userId) => {
console.log(`User ${userId} logged in`);
});
bus.emit("login", "u_123");
bus.emit("login", "u_456");// app.js
import express from "express";
const app = express();
app.use(express.json());
app.post("/users", (req, res) => {
const { email } = req.body;
if (!email?.includes("@")) {
return res.status(400).json({ error: "Invalid email" });
}
res.status(201).json({ id: crypto.randomUUID(), email });
});
app.listen(3000, () => console.log("http://localhost:3000"));// app.ts
import express, { type Request, type Response } from "express";
const app = express();
app.use(express.json());
interface CreateUserBody {
email: string;
}
app.post("/users", (req: Request<{}, unknown, CreateUserBody>, res: Response) => {
const { email } = req.body;
if (!email?.includes("@")) {
return res.status(400).json({ error: "Invalid email" });
}
res.status(201).json({ id: crypto.randomUUID(), email });
});
app.listen(3000, () => console.log("http://localhost:3000"));