¡Ven a la JSConf España 2026! Comprar entradas

Importante al instalar cualquier paquete en Node.js

Cuando instalas un paquete en Node.js no solo se descarga una dependencia y ya está. Ocurren varias cosas importantes que conviene entender bien, porque aquí nacen muchos bugs, sustos y problemas de seguridad.

En esta clase vamos a ver qué pasa realmente al instalar un paquete, cómo funcionan las versiones y por qué ese símbolo que aparece en el package.json no está ahí por casualidad.

Qué archivos se modifican al instalar un paquete

Cuando ejecutas un pnpm add (o npm install), pasan tres cosas clave:

  1. 📝 Se actualiza el package.json: Describe qué necesita tu proyecto para funcionar.
  2. 🔒 Se genera o modifica el lockfile (pnpm-lock.yaml o package-lock.json): Es una foto exacta de las versiones concretas que se han instalado.
  3. 📥 Se descargan las dependencias en node_modules: Contiene el código real que se importa cuando usas una dependencia.

Recuerda: node_modules es donde vive el código físico, pero package.json es el mapa que dice qué debe haber ahí.

De dónde salen las dependencias al hacer un import

Cuando haces un import de un paquete, Node.js no va a internet ni a npm. Lo que hace es:

  1. Buscar en la carpeta node_modules.
  2. Cargar la versión que esté instalada ahí.

Por eso es tan importante entender qué versión exacta se ha instalado y por qué.

El símbolo misterioso en las versiones: el caret (^)

Después de instalar un paquete, es muy habitual ver algo así en el package.json:

{
  "dependencies": {
    "ms": "^2.3.2"
  }
}

Ese simbolito ^ no está ahí porque sí. Se llama caret.

Qué es el caret (^)

El caret indica un rango de versiones permitidas, no una versión exacta. Está directamente relacionado con el versionado semántico o SemVer.

Qué es el versionado semántico (SemVer)

Las versiones siguen este formato estándar: major.minor.patch. Ejemplo: 2.3.2

  • 🔴 Major: Cambios grandes y breaking changes (rompen la compatibilidad).
  • 🟡 Minor: Nuevas funcionalidades compatibles.
  • 🟢 Patch: Correcciones de bugs o parches de seguridad.

En teoría:

  • Cambiar el Major puede romper tu código.
  • Cambiar el Minor añade cosas sin romper.
  • Cambiar el Patch solo arregla problemas.

La realidad: En la práctica, no siempre se respeta al 100%, y ahí vienen los problemas. Un cambio en la versión minor podría introducir un bug inesperado o un cambio de comportamiento que no tenías previsto.

Qué significa exactamente ^2.3.2

El caret delante de una versión quiere decir:

“Se permite cualquier versión mayor o igual a 2.3.2, siempre que sea menor que 3.0.0.”

Es decir, se podrían instalar automáticamente:

  • 2.3.3
  • 2.9.9
  • 2.58.1000

Pero nunca se instalará la 3.0.0.

Por qué esto puede ser problemático

Aunque parezca una buena idea para tener parches de seguridad automáticos, este comportamiento ha provocado:

  • 🐛 Bugs inesperados: Una actualización minor que introduce un error.
  • 📉 Cambios de comportamiento: El código funciona distinto sin que hayas tocado nada.
  • 🛡️ Ataques de supply chain: Un atacante toma el control de un paquete y sube una versión maliciosa (ej. 2.3.4) que se instala sola en tu servidor.

Cuándo tiene sentido quitar el caret

Si quieres control total sobre las dependencias y evitar sorpresas, una estrategia válida es quitar el caret y dejar la versión exacta:

"dependencies": {
  "ms": "2.3.2"
}

Así te aseguras de que:

  • Siempre se instala esa versión concreta.
  • No hay actualizaciones silenciosas.
  • El entorno es reproducible (lo que funciona en tu máquina funcionará igual en el servidor).

El papel del lockfile

Aunque el package.json tenga rangos, el lockfile (pnpm-lock.yaml, package-lock.json, etc.) fija exactamente qué versión se instaló en ese momento.

Por eso:

  • No deberías borrar el lockfile a la ligera.
  • Es clave para que todos los entornos usen lo mismo.
  • Evita sorpresas entre máquinas y despliegues.

¡Ya casi estamos!

Al instalar paquetes en Node.js:

  1. No solo importa qué paquete usas, sino qué versión y qué rango permites.
  2. El caret permite actualizaciones automáticas, lo cual es cómodo pero arriesgado.
  3. Quitar el caret te da más control y estabilidad.

Entender esto te ahorrará muchísimos problemas “misteriosos” cuando empiezas a trabajar en backend y proyectos reales.

En la siguiente clase seguiremos profundizando en Node.js y su ecosistema, ya con ejemplos más prácticos.