Cierras el Módulo 4 con una plataforma web completa —servidor, enrutador, estáticos, pedidos, cliente HTTP— y sin una sola dependencia externa. Fue una decisión deliberada y ha tenido un valor pedagógico enorme: ahora sabes qué hay debajo. Pero también ha tenido un precio que has pagado a mano, línea a línea: compilar patrones de ruta, parsear cuerpos, mantener una tabla de tipos MIME, calcular ETags.

Ese precio no siempre merece la pena pagarlo. En un proyecto real hay cientos de problemas ya resueltos por otras personas, mejor de lo que los resolverías tú en una tarde, y probados por millones de instalaciones. El oficio consiste en saber cuándo apoyarse en ese trabajo y cuándo no, y para eso hace falta entender la maquinaria: npm.

Hasta ahora Escena Viva ha vivido sin package.json. Se ejecuta con node src/... y funciona. En esta lección eso cambia: le damos al proyecto una identidad formal, un manifiesto que declara qué es, con qué versión de Node se ejecuta y —a partir de la lección siguiente— de qué depende.

Contenido

  1. Qué es npm: dos cosas con el mismo nombre
  2. El ecosistema y sus alternativas: yarn, pnpm, bun
  3. npm init: el manifiesto de Escena Viva
  4. Los campos de package.json, uno a uno
  5. El package.json completo de Escena Viva
  6. node_modules: qué es y por qué nunca se sube
  7. npm install sin argumentos
  8. npx: ejecutar sin instalar
  9. Dónde vive la configuración: npm config y .npmrc

  1. Qué es npm: dos cosas con el mismo nombre

Cuando alguien dice "npm" puede estar hablando de dos cosas distintas, y confundirlas genera malentendidos constantes.

El registro La herramienta
Qué es Un servidor público de paquetes en https://registry.npmjs.org El programa de línea de comandos npm
Qué hace Almacena y sirve paquetes publicados por cualquiera Descarga, instala, versiona, publica y ejecuta scripts
Se sustituye por Registros privados (Verdaccio, Artifactory, GitHub Packages) yarn, pnpm, bun
Se instala No, es un servicio Viene incluido con Node.js

La segunda fila es la importante: el registro y la herramienta son intercambiables por separado. Puedes usar pnpm contra el registro público, o npm contra un registro interno de tu empresa. No están casados.

Comprueba que ya tienes la herramienta, porque el instalador de Node la trajo consigo:

node -v     # v24.5.0
npm -v      # 11.x.y

Si usas nvm o fnm, cada versión de Node trae su propio npm. Al cambiar de versión de Node con nvm use, cambias también de npm sin darte cuenta. Es normal y es lo correcto.

Por qué es el mayor ecosistema del mundo

El registro público supera los tres millones de paquetes, más que cualquier otro ecosistema de lenguaje. Las razones son estructurales:

  • JavaScript se ejecuta en todas partes: navegador, servidor, móvil, escritorio, funciones sin servidor. Un mismo registro sirve a todos esos mundos.
  • Publicar es trivial: un package.json con tres campos y npm publish. No hay comité de revisión.
  • La biblioteca estándar de JavaScript fue históricamente pequeña. Donde otros lenguajes traen de fábrica manejo de fechas o utilidades de colecciones, JavaScript no lo hacía, y el hueco lo llenó el registro. De ahí su fama de fragmentado y los paquetes de una sola función. Hoy el núcleo de Node ha crecido mucho —lo has comprobado en cuatro módulos— y muchas dependencias clásicas ya no hacen falta.

El reverso de "publicar es trivial" es que cualquiera puede publicar cualquier cosa. Eso convierte la elección de dependencias en una decisión de ingeniería, no en un trámite: lo veremos en 05-02 con una lista de comprobación y en 05-06 desde la seguridad.

  1. El ecosistema y sus alternativas: yarn, pnpm, bun

La herramienta npm no es la única que sabe leer un package.json e instalar dependencias.

Herramienta Fichero de bloqueo Estructura en disco Punto fuerte Punto débil
npm package-lock.json Árbol aplanado en node_modules Viene con Node; cero instalación; universal Ni el más rápido ni el más compacto
yarn (moderno) yarn.lock Aplanado o Plug'n'Play sin node_modules Espacios de trabajo maduros, PnP PnP rompe herramientas que asumen node_modules
pnpm pnpm-lock.yaml Almacén global + enlaces duros Ahorro de disco brutal; estricto con dependencias no declaradas Enlaces confunden a alguna herramienta antigua
bun bun.lock Aplanado, instalador propio Velocidad extrema; es también un runtime Ecosistema joven; compatibilidad no total

La idea de pnpm merece un párrafo porque es genuinamente distinta. En vez de copiar cada paquete dentro del node_modules de cada proyecto, guarda una sola copia de cada versión en un almacén global de tu máquina (~/.local/share/pnpm/store) y en el proyecto crea enlaces. Si tienes diez proyectos que usan [email protected], en disco hay un express, no diez: en un portátil con veinte repositorios el ahorro se mide en gigabytes. Además pnpm es estricto: si tu código hace require('cualquier-cosa') sin haberlo declarado, falla. Con npm suele funcionar por accidente, porque el aplanamiento deja esa dependencia transitiva visible en la raíz (05-02).

Por qué este curso usa npm, aun sabiendo que hay opciones más rápidas: viene con Node (cero instalación, cero divergencia entre máquinas); es el denominador común que entienden toda la documentación y todos los sistemas de integración continua; y los conceptos son los mismos —package.json, semver, lock, scripts, registro—, así que pasar a pnpm son cinco minutos de tabla de equivalencias.

Regla práctica de convivencia: una sola herramienta por proyecto. Mezclar npm install y yarn add en el mismo repositorio genera dos ficheros de bloqueo contradictorios y horas de depuración inútil.

  1. npm init: el manifiesto de Escena Viva

El package.json es un fichero JSON en la raíz del proyecto que cumple cuatro papeles a la vez: identidad (cómo se llama, qué versión tiene, quién lo mantiene), contrato de ejecución (qué versión de Node necesita, si es CommonJS o ESM, cuál es su punto de entrada), declaración de dependencias (05-02 y 05-03) e interfaz de tareas con el campo scripts (05-04).

Crearlo es una sola orden. Desde la raíz del proyecto:

cd ~/escena-viva
npm init

npm init abre un cuestionario interactivo con valores por defecto entre paréntesis; pulsar Intro acepta el propuesto:

package name: (escena-viva)
version: (1.0.0) 0.1.0
description: Plataforma de venta de entradas para eventos culturales
entry point: (index.js) src/servidor/servidor.js
test command:
git repository:
keywords: entradas,eventos,teatro
author: Equipo Escena Viva <[email protected]>
license: (ISC) MIT

Dos detalles: el nombre por defecto es el de la carpeta —si la tuya se llama Escena Viva, con mayúsculas y espacio, npm init protestará por las reglas del apartado siguiente—; y hemos puesto 0.1.0, no 1.0.0, porque el valor por defecto de npm significa "API estable, prometo compatibilidad" y eso es una mala promesa para un proyecto que empieza. En 05-03 haremos ese salto conscientemente.

Si quieres saltarte el cuestionario y aceptar todos los valores por defecto:

npm init -y      # equivale a --yes

Genera un package.json mínimo en un instante. Es perfecto para un laboratorio desechable, y siempre puedes editarlo después: package.json es un fichero de texto normal, no hay nada mágico en él. De hecho, editarlo a mano es lo habitual una vez el proyecto existe.

  1. Los campos de package.json, uno a uno

name

El identificador del paquete. Sus reglas son estrictas porque acaba formando parte de una URL: máximo 214 caracteres, solo minúsculas (EscenaViva no vale), sin espacios —se usan guiones: escena-viva—, no puede empezar por . ni _, y debe ser URL-safe: nada de tildes, ñ ni ·.

Existe una variante con ámbito (scope), un prefijo con arroba: @escena-viva/formato. El ámbito es un espacio de nombres reservado para una persona u organización, y tiene tres ventajas: evita colisiones (@escena-viva/formato es tuyo aunque formato esté cogido), agrupa paquetes de un mismo equipo, y es privado por defecto al publicar, lo que evita filtraciones accidentales (05-05). Los verás constantemente: @babel/core, @types/node, @eslint/js.

version

La versión actual del paquete en formato semver: MAYOR.MENOR.PARCHE. Es obligatoria para publicar y es el eje de toda la lección 05-03. Por ahora quédate con que 0.1.0 comunica "esto todavía se mueve".

description y keywords

Texto libre y lista de palabras clave. Son metadatos de búsqueda: alimentan el buscador de npmjs.com. En un paquete privado no sirven para nada funcional, pero description sigue siendo útil como recordatorio de qué es este repositorio.

main

El fichero que se carga cuando alguien hace require('escena-viva'). Es el punto de entrada de la biblioteca, no necesariamente el ejecutable. Si se omite, Node busca index.js en la raíz.

En Escena Viva apuntamos a src/servidor/servidor.js, que exporta crearServidor sin arrancar nada gracias al require.main === module del Módulo 4. Es exactamente lo que se quiere de un punto de entrada: importar no debe tener efectos secundarios.

El campo moderno que sustituye a main con mucho más control se llama exports, y lo veremos en 05-05 al construir un paquete publicable.

type

Decide cómo interpreta Node los ficheros .js de este proyecto:

Valor Ficheros .js se leen como require import
"commonjs" (por defecto) CommonJS Sí Solo dinámico, o en .mjs
"module" ES Modules No (usa .cjs) Sí

En el Módulo 2 mencionamos esta línea sin desarrollarla; ahora ya tiene sitio donde vivir. Escena Viva declara "type": "commonjs" explícitamente. Es el valor por defecto, así que técnicamente sobra, pero escribirlo elimina toda ambigüedad para quien lea el proyecto y para las herramientas.

engines

Declara qué versiones de Node admite el proyecto:

"engines": {
  "node": ">=24.5.0 <25"
}

Esto debe ser coherente con el .nvmrc que creaste en el Módulo 1, pero son dos ficheros con públicos distintos: .nvmrc lo leen nvm, fnm, Volta y la CI, y cambia tu versión activa de Node; engines lo leen npm y las plataformas de despliegue, y avisa o falla si la versión no encaja. Por defecto solo avisa; para que sea un error real hay que activarlo en el .npmrc del apartado 9.

private

"private": true

Un interruptor de seguridad: con private: true, npm publish se niega a ejecutarse. Nada más, y nada menos.

Escena Viva es una aplicación, no una biblioteca: no debe acabar nunca en el registro público. Poner private: true en toda aplicación es una costumbre barata que ha evitado muchas filtraciones de código propietario por un npm publish tecleado en la carpeta equivocada. Solo se quita cuando de verdad quieres publicar, que es lo que haremos en 05-05 con el paquete @escena-viva/formato.

license

Identificador SPDX de la licencia: MIT, Apache-2.0, GPL-3.0-only, ISC. Para código cerrado, el valor convencional es:

"license": "UNLICENSED"

No es un campo decorativo: en 05-06 veremos cómo se auditan las licencias de todo el árbol de dependencias, y ese análisis se apoya justo en este campo.

author y repository

"author": "Equipo Escena Viva <[email protected]>",
"repository": {
  "type": "git",
  "url": "git+https://github.com/escena-viva/escena-viva.git"
}

repository es más útil de lo que parece: npm repo <paquete> abre esa URL, y las herramientas de auditoría la usan para localizar el código fuente de una dependencia. Cuando estés investigando si un paquete es de fiar, la ausencia de repository ya es una señal.

  1. El package.json completo de Escena Viva

Este es el manifiesto con el que arrancamos el módulo. Todavía no tiene dependencias —llegan en 05-02— ni scripts útiles —llegan en 05-04—, y su versión es 0.1.0.

{
  "name": "escena-viva",
  "version": "0.1.0",
  "private": true,
  "description": "Plataforma de venta de entradas para eventos culturales",
  "keywords": ["entradas", "eventos", "teatro", "aforo"],
  "license": "MIT",
  "author": "Equipo Escena Viva <[email protected]>",
  "type": "commonjs",
  "main": "src/servidor/servidor.js",
  "engines": {
    "node": ">=24.5.0 <25"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/escena-viva/escena-viva.git"
  },
  "scripts": {
    "start": "node src/servidor/servidor.js"
  }
}

Repasa lo que dice ese fichero a quien lo lea por primera vez, sin abrir nada más: es una plataforma de venta de entradas, versión temprana, privada (no se publica), CommonJS, necesita Node 24, se arranca con npm start y su código vive en un repositorio git conocido. Ocho líneas de metadatos que ahorran una conversación entera.

Un aviso: package.json es JSON estricto, sin comentarios, sin comas finales y con comillas dobles. Si npm falla con Unexpected token, casi siempre es una coma de más antes de un }. Comprueba que npm lo entiende:

npm pkg get name version engines
{
  "name": "escena-viva",
  "version": "0.1.0",
  "engines": {
    "node": ">=24.5.0 <25"
  }
}

npm pkg get y npm pkg set leen y escriben campos sin abrir el editor, respetando el formato. Son la forma correcta de tocar el manifiesto desde un script:

npm pkg set description="Venta de entradas para eventos culturales"

  1. node_modules: qué es y por qué nunca se sube

node_modules es la carpeta donde npm deposita el código de las dependencias descargadas. Aún no existe en Escena Viva porque no hay dependencias, pero conviene entenderla antes de crearla.

Cuando en el Módulo 2 estudiaste la resolución de require, viste que Node, ante require('algo') sin ./, sube por el árbol de directorios buscando node_modules/algo en cada nivel. npm es simplemente quien llena esas carpetas: escribe ficheros donde Node ya sabía mirar, sin magia adicional. Y es una carpeta enorme: un proyecto Express modesto ronda los 40.000 ficheros.

Nunca se sube al control de versiones. Las razones, por orden de importancia:

Razón Explicación
Es reproducible package.json + package-lock.json bastan para reconstruirla idéntica. Guardar el resultado además del origen es redundante.
Tamaño y ruido Decenas de miles de ficheros convierten cada git status y cada revisión de código en algo inmanejable.
Contenido binario y por plataforma Algunos paquetes compilan binarios nativos para tu sistema operativo y arquitectura. Lo que funciona en tu macOS puede no arrancar en el Linux del servidor.
Conflictos imposibles Un conflicto de fusión dentro de node_modules no se resuelve; se borra y se reinstala.

Por eso el .gitignore que creaste en el Módulo 1 ya empezaba por esa línea:

node_modules/
.env
informes/*.csv
*.log

La primera línea es la crítica. La segunda también lo será a partir de la próxima lección, cuando dotenv entre en juego. Y ojo con la asimetría, que es la fuente de confusión más común del módulo:

  • node_modules/ → se ignora (es el resultado).
  • package.json y package-lock.json → se suben siempre (son la fuente).

  1. npm install sin argumentos

Ejecutado sin nombre de paquete, npm install (o su alias npm i) significa: "pon este proyecto en condiciones de ejecutarse". Es lo primero que teclea cualquiera tras clonar un repositorio.

Sus pasos exactos, en orden: lee package.json y reúne dependencies y devDependencies; lee package-lock.json si existe, para conocer el árbol ya resuelto; compara con lo instalado y calcula qué falta o sobra; descarga del registro lo que falte, usando la caché local si lo tiene; verifica la integridad de cada paquete con su hash (integrity); extrae a node_modules aplanando el árbol; enlaza los ejecutables en node_modules/.bin (clave para 05-04); ejecuta los scripts de instalación de los paquetes que los tengan (postinstall — atención, 05-06); y por último actualiza package-lock.json si hubo que resolver algo nuevo.

Ese último paso es la diferencia esencial con npm ci, y le dedicaremos una tabla entera en 05-03: npm install puede modificar el lock; npm ci no lo toca jamás.

En Escena Viva, hoy, el resultado es anticlimático y didáctico:

npm install
up to date, audited 1 package in 231ms

found 0 vulnerabilities

"1 package" es el propio proyecto. Cero dependencias, cero vulnerabilidades: el estado más seguro posible, y el punto de partida contra el que compararemos todo lo que añadamos.

  1. npx: ejecutar sin instalar

Hay dos formas de usar una herramienta de línea de comandos publicada en npm.

La forma antigua, instalación global:

npm install -g cowsay      # se instala en tu sistema, fuera del proyecto
cowsay "Hola Escena Viva"

La forma recomendable, npx:

npx cowsay "Hola Escena Viva"

npx busca en este orden: si el ejecutable existe en node_modules/.bin del proyecto, lo usa; si está en la caché de npx, lo usa; y si no, lo descarga a una caché temporal, lo ejecuta y no lo instala en el proyecto.

Instalación global (-g) npx
Dónde queda En tu sistema, para siempre En la caché; no ensucia el proyecto
Versión La que instalaste hace meses La declarada por el proyecto, o la última
Coherencia en equipo Cada uno tiene la suya Todos usan la misma
Uso ideal Herramientas de uso diario ajenas a proyectos Casi todo lo demás

El problema real de -g no es el espacio en disco, es la deriva de versiones: tú generas un proyecto con la versión global que instalaste en marzo y tu compañero con la que instaló ayer, y los resultados difieren sin que nadie entienda por qué.

Puedes fijar la versión, que es lo aconsejable en documentación y en CI:

npx create-express-app@latest mi-app
npx eslint@9 src

Y el punto que cierra el círculo: si el proyecto declara una herramienta en devDependencies, npx eslint usa esa copia local, sin descargar nada. Esa es la razón por la que en 05-04 podremos escribir "lint": "eslint src" en los scripts sin instalar ESLint globalmente.

  1. Dónde vive la configuración: npm config y .npmrc

npm se configura por capas. Para ver el resultado efectivo:

npm config list
; "user" config from /home/usuario/.npmrc
init-author-name = "Equipo Escena Viva"

; node bin location = /home/usuario/.nvm/versions/node/v24.5.0/bin/node
; cwd = /home/usuario/escena-viva
; npm version = 11.4.2

Con npm config list -l verás además todos los valores por defecto. Las capas se aplican en este orden, de mayor a menor prioridad:

Capa Ubicación Uso típico
Línea de comandos --registry=... Una ejecución concreta
Variables de entorno NPM_CONFIG_REGISTRY CI y contenedores
.npmrc de proyecto ./.npmrc Se sube al repo: política del equipo
.npmrc de usuario ~/.npmrc No se sube: tus tokens
.npmrc global Junto a la instalación de npm Rara vez se toca
Valores por defecto Integrados —

El .npmrc de proyecto de Escena Viva, que sí va al repositorio:

# Falla la instalacion si la version de Node no cumple "engines"
engine-strict=true

# Al usar "npm install <paquete>", guarda un rango exacto en vez de "^"
# (lo justificaremos en 05-03; de momento queda anotado)
save-exact=false

# Registro por defecto, explicito para que nadie lo dude
registry=https://registry.npmjs.org/

engine-strict=true convierte el aviso de engines en un error: si alguien intenta instalar el proyecto con Node 22, npm se planta. Combinado con .nvmrc, la versión de Node deja de ser una convención de pasillo y pasa a ser una regla verificada.

Y la advertencia más importante del apartado: el .npmrc de usuario (~/.npmrc) contiene tus tokens de autenticación, en líneas del estilo //registry.npmjs.org/:_authToken=npm_xxxxxxxx. Ese fichero no se sube nunca a ningún sitio: un token filtrado en un repositorio público permite a cualquiera publicar paquetes en tu nombre (05-05 y 05-06).

Por último, el registro por defecto es https://registry.npmjs.org/. Cambiarlo tiene dos casos de uso legítimos: un espejo interno de empresa y un registro privado para paquetes propietarios, normalmente combinado con ámbitos:

# Solo los paquetes @escena-viva/* van al registro interno
@escena-viva:registry=https://registro.interno.test/

Errores Comunes y Consejos

  • Ejecutar npm init en la carpeta equivocada. Comprueba con pwd antes. Si te equivocas, borra el package.json creado: un manifiesto huérfano en tu carpeta personal hace que npm trate toda esa carpeta como un proyecto.
  • Un package.json inválido. Sin comentarios, sin comas finales, con comillas dobles. Valida rápido con node -e "require('./package.json')": si no imprime error, es JSON correcto.
  • Confundir main con "el fichero que arranca la aplicación". main es lo que se obtiene al importar el paquete; lo que arranca la aplicación es scripts.start. Que aquí coincidan es una comodidad, no una regla.
  • Subir node_modules por olvidar el .gitignore. Si ya lo has subido: git rm -r --cached node_modules, añade la línea y confirma. El historial seguirá pesando, pero el daño deja de crecer.
  • Instalar herramientas con -g por costumbre. Cada -g es una versión que solo existe en tu máquina. Usa npx, o declárala en devDependencies.
  • Consejo: npm init -y seguido de npm pkg set. Más rápido que el cuestionario y automatizable en una plantilla de proyecto. Y usa npm pkg get en vez de leer el fichero con grep: devuelve JSON válido y no se rompe con cambios de formato.

Ejercicios

Ejercicio 1. Crear el manifiesto de Escena Viva. Desde la raíz del proyecto, ejecuta npm init y responde el cuestionario para producir exactamente el package.json del apartado 5: nombre escena-viva, versión 0.1.0, licencia MIT, punto de entrada src/servidor/servidor.js. Después añade a mano private, type y engines. Verifica con npm pkg get y comprueba que npm start arranca el servidor del Módulo 4.

Ejercicio 2. Comprobar que engine-strict funciona. Crea el .npmrc de proyecto con engine-strict=true. Cambia temporalmente engines.node a ">=99.0.0" y ejecuta npm install. Observa el error exacto. Después quita engine-strict y repite: ¿qué cambia? Deja el fichero como estaba.

Ejercicio 3. npx frente a -g. Sin instalar nada globalmente, ejecuta npx [email protected] "Aforo 3000" y anota qué imprime npx la primera vez y qué imprime la segunda. Luego busca dónde queda la caché con npm config get cache y explica en dos frases por qué npx da resultados más reproducibles en un equipo que una instalación global.

Soluciones

Solución 1. Tras el cuestionario, el fichero generado no incluye private, type ni engines; se añaden a mano o con npm pkg:

npm pkg set private=true --json
npm pkg set type="commonjs"
npm pkg set engines.node=">=24.5.0 <25"
npm pkg set scripts.start="node src/servidor/servidor.js"

El --json de la primera línea es imprescindible: sin él, private se guardaría como la cadena "true" y no como el booleano true, y npm no lo interpretaría como interruptor. Es el error más frecuente con npm pkg set.

Después, npm start debe arrancar el servidor exactamente igual que node src/servidor/servidor.js, porque literalmente es eso lo que ejecuta.

Solución 2. Con engine-strict=true y engines.node imposible:

npm error code EBADENGINE
npm error engine Unsupported engine
npm error engine Not compatible with your version of node/npm: [email protected]
npm error notsup Required: {"node":">=99.0.0"}
npm error notsup Actual:   {"npm":"11.4.2","node":"v24.5.0"}

La instalación se detiene con código de salida distinto de cero. Sin engine-strict, el mismo caso produce solo un npm warn EBADENGINE y la instalación continúa. La diferencia importa sobre todo en la CI del Módulo 11: un aviso pasa desapercibido en un registro de miles de líneas; un fallo detiene el despliegue.

Solución 3. La primera ejecución descarga el paquete y lo anuncia:

Need to install the following packages:
[email protected]
Ok to proceed? (y)

La segunda lo encuentra en la caché y se ejecuta al instante, sin preguntar. La caché vive donde diga npm config get cache (~/.npm/_npx para los ejecutables temporales).

La reproducibilidad viene de dos cosas: npx paquete@version fija la versión en el propio comando, de modo que el mismo comando produce el mismo resultado en cualquier máquina; y cuando el proyecto declara la herramienta en devDependencies, npx usa la copia local del proyecto, que está fijada en package-lock.json y es idéntica para todo el equipo. Una instalación global no ofrece ninguna de las dos garantías: depende de cuándo instaló cada persona.

Conclusión

Escena Viva ya tiene manifiesto. Has visto que npm son dos cosas: un registro público con más de tres millones de paquetes y una herramienta de línea de comandos que viene incluida con Node, y que ambas se pueden sustituir por separado —el curso usa npm por ubicuidad, sabiendo que pnpm ahorra disco con su almacén global y enlaces, y que yarn y bun juegan la misma partida con otras reglas.

El package.json que has creado cumple los cuatro papeles del apartado 3: identidad (name, version, description, author, repository), contrato de ejecución (type: commonjs, main, engines coherente con el .nvmrc del Módulo 1), y los dos huecos que llenaremos enseguida: dependencias y scripts. Y lleva private: true, el interruptor barato que impide que una aplicación acabe publicada por accidente.

Sabes también que node_modules es solo el sitio donde npm deposita lo que Node ya sabía buscar desde el Módulo 2, que nunca se sube al repositorio porque es reproducible a partir de package.json y del lock, y que npm install sin argumentos ejecuta nueve pasos muy concretos —de los cuales el último, tocar el lock, es justo el que npm ci no hace—. Que npx ejecuta herramientas sin instalarlas y evita la deriva de versiones que provoca el -g. Y que la configuración vive en capas, con un .npmrc de proyecto que se sube (engine-strict=true) y uno de usuario que contiene tus tokens y no se sube jamás.

En la lección siguiente, Instalación y Uso de Paquetes, rompemos por fin la racha de cero dependencias: instalaremos las primeras, distinguiremos dependencies de devDependencies y por qué esa distinción cambia el tamaño y la seguridad de lo que despliegas, y —más importante que cualquier comando— construiremos una lista de comprobación para decidir si una dependencia merece entrar en el proyecto. Porque después de escribir un módulo entero sin ninguna, ya sabes que la respuesta no siempre es que sí.

Curso de Node.js: De Principiante a Avanzado

Módulo 1: Introducción a Node.js

Módulo 2: Conceptos Básicos

Módulo 3: Sistema de Archivos y E/S

Módulo 4: HTTP y Servidores Web

Módulo 5: NPM y Gestión de Paquetes

Módulo 6: Framework Express.js

Módulo 7: Bases de Datos y ORMs

Módulo 8: Autenticación y Autorización

Módulo 9: Pruebas y Depuración

Módulo 10: Temas Avanzados

Módulo 11: Despliegue y DevOps

Módulo 12: Proyectos del Mundo Real

© Copyright 2026. Todos los derechos reservados