El pipeline termina antes de los tests porque npm ci encontró un package.json que no coincide con package-lock.json. La reacción habitual es cambiar el comando por npm install hasta que el job quede en verde. Eso oculta el origen del problema: CI acaba de descubrir que el repositorio no describe un único árbol de dependencias.

La regla práctica es sencilla: usa npm install para agregar o actualizar dependencias durante el desarrollo. Usa npm ci en CI cuando el lockfile ya fue revisado y debe restaurarse sin cambios. Si los archivos difieren, corrige el manifiesto y el lockfile en la rama, en lugar de dejar que el pipeline elija una versión nueva.

La instalación de dependencias forma parte del contrato de entrega. La guía de GitLab CI para Node.js cubre la estructura general de un pipeline. Aquí nos concentramos en la decisión que ocurre antes del typecheck, los tests y el build.

La decisión también conecta con dos controles cercanos: un AGENTS.md ligero para agentes de código puede registrar el comando esperado, y las pruebas unitarias y de integración en Node.js validan lo que ocurre después de instalar.

Diagrama que compara npm install editando package.json con npm ci verificando el lockfile en un pipeline de CI.

Respuesta corta

  • Ejecuta npm install cuando cambies dependencias o regeneres el lockfile.
  • Ejecuta npm ci en jobs automatizados que deban instalar el estado aprobado.
  • Si npm ci falla, compara los dos archivos antes de cambiar el comando.

¿Cuándo debes usar npm install?

npm install es el comando que cambia el proyecto. Instala las dependencias y puede actualizar package-lock.json cuando el rango de package.json ya no coincide con el lockfile. La documentación de npm sobre npm install, consultada el 26 de octubre de 2026, describe el manifiesto como la fuente de los rangos aceptables y el lockfile como el registro de las versiones resueltas.

Úsalo cuando:

  • agregues, quites o actualices una dependencia;
  • cambies un rango de versión en package.json;
  • regeneres el lockfile después de una actualización revisada;
  • necesites resolver dependencias localmente y revisar el diff resultante.

Después de ese cambio, confirma package.json y package-lock.json juntos. Si solo se confirma uno, el siguiente npm ci puede detectar que la descripción del proyecto quedó incompleta.

¿Cuándo debes usar npm ci en CI?

npm ci es la opción normal para un job automatizado que debe restaurar el estado descrito por el lockfile. En 2026, la documentación de npm sobre npm ci, consultada el 26 de octubre, dice que el proyecto necesita package-lock.json o npm-shrinkwrap.json, que el comando falla cuando el lockfile no coincide con el manifiesto y que no escribe esos archivos.

Usa npm ci cuando el lockfile esté versionado, los dos archivos estén sincronizados, el job conozca la versión de Node que debe usar, las opciones de resolución estén registradas y la instalación vaya seguida de typecheck, tests o build.

La guía de lockfiles de setup-node, consultada el 26 de octubre de 2026, recomienda confirmar el lockfile y usar npm ci para proyectos npm en CI. Es una orientación de flujo de trabajo, no una configuración para copiar sin revisión. El proyecto aún debe definir su versión de Node, sus scripts y sus requisitos de plataforma.

npm ci no es un comando de reparación. Si informa una diferencia, el resultado correcto es un error que alguien corrige en el repositorio. Ejecutar npm install dentro del job para ocultar el error convierte la verificación en una mutación. El siguiente job podría probar un árbol que el commit no registra.

Qué ocurre cuando package.json y el lockfile difieren

Imagina un proyecto cuyo lockfile contiene is-number@7.0.0. Si alguien cambia el manifiesto a ^6.0.0 sin ejecutar npm install, CI no tiene una respuesta segura que conserve ambos archivos. npm ci debe rechazar la instalación y pedir que la rama actualice el lockfile.

Comprobé este caso en un fixture temporal el 26 de octubre de 2026, con Node v25.5.0 y npm 11.8.0. Instalé is-number@7.0.0, cambié solamente la dependencia de package.json a ^6.0.0 y ejecuté npm ci. El comando terminó con estado 1 e informó que is-number@7.0.0 no satisfacía is-number@6.0.0.

La reparación quedó separada de la verificación:

# En la rama de desarrollo, después de revisar el cambio
npm install

# Revisa qué cambió en los archivos de dependencias
git diff -- package.json package-lock.json

# En una copia limpia, confirma el estado aprobado
npm ci

En el mismo fixture, npm install actualizó el lockfile a 6.0.0. Un npm ci posterior instaló esa versión. Esto demuestra el contrato de archivos en un caso pequeño. No es un benchmark, no cubre todas las formas de workspace y no prueba todos los formatos de lockfile.

Un job mínimo que conserva esa separación

El siguiente ejemplo es ilustrativo. Adapta la versión de la acción, la versión de Node y los scripts al repositorio real:

name: verify

on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test
      - run: npm run build

El YAML es ilustrativo. Usa las versiones de acciones y los scripts que el repositorio mantenga. La orientación actual de setup-node sobre cache y lockfiles explica la relación entre la cache, el lockfile y npm ci. No garantiza que una cache pueda ocultar una instalación inválida.

No mezcles el paso que cambia dependencias con el paso que verifica un commit. Si una actualización automatizada necesita ejecutar npm install, ponla en otro job, produce el diff y exige revisión antes de aceptar el lockfile.

Por qué npm ci puede seguir fallando

Un fallo de npm ci no significa automáticamente que el comando sea incorrecto. Empieza por el mensaje y revisa el límite que identifica.

El manifiesto y el lockfile están desincronizados

Este es el caso principal. Compara dependencias, overrides, workspaces y versiones declaradas. La documentación de npm también advierte que opciones como --legacy-peer-deps y --install-links usadas al crear el lockfile deben repetirse en npm ci, o la resolución puede fallar. Cuando corresponda, registra esas opciones en la configuración del proyecto en vez de depender de la memoria de una máquina local.

Workspaces o dependencias file:

Los workspaces y las dependencias file: amplían la superficie del lockfile. Un issue de npm CLI sobre dependencias basadas en archivos, consultado el 26 de octubre de 2026, registra un fallo específico de versión en el que npm ci rechazó un árbol después de npm install. Trátalo como una pista para revisar versiones de npm, forma de las dependencias y una reproducción mínima. No lo conviertas en una regla para todos los proyectos.

Diferencia entre plataforma y entorno

Algunas dependencias nativas o específicas de arquitectura pueden fallar aunque los archivos coincidan. Un issue de npm CLI sobre paquetes relacionados con arquitectura, consultado el 26 de octubre de 2026, es evidencia de un caso que requiere revisar versiones, plataforma y lockfile, no de que npm install sea siempre mejor.

Registra el sistema del runner, las versiones de Node y npm, la configuración del proyecto y el error completo. Después reduce el problema a un fixture. Cambiar a npm install sin conservar esa evidencia solo mueve el error.

Scripts de instalación

Una instalación limpia no es un sandbox. npm puede ejecutar scripts de ciclo de vida necesarios para compilar una dependencia nativa o preparar el proyecto. Una discusión pública sobre scripts de npm y fuentes no pertenecientes al registry, consultada el 26 de octubre de 2026, muestra la preocupación operativa, pero no reemplaza la documentación de la versión de npm que usa tu equipo.

Decisión rápida

Situación Comando Motivo
Agregar o actualizar una dependencia npm install Cambia y registra el árbol resuelto
Verificar un commit en CI npm ci Rechaza diferencias en vez de escribirlas
Reparar un lockfile desactualizado npm install localmente Produce un diff revisable
Repetir una instalación en deploy npm ci Reproduce el estado confirmado

Lista de comprobación antes de cambiar el comando

  1. ¿El commit incluye package.json y package-lock.json cuando ambos cambiaron?
  2. ¿La versión de Node y npm del runner es la que el proyecto espera?
  3. ¿Se usaron opciones como --legacy-peer-deps para generar el lockfile?
  4. ¿El proyecto tiene workspaces o dependencias file: que requieren una reproducción mínima?
  5. ¿La causa es la plataforma o un script de instalación, en lugar del comando?
  6. ¿El job ejecuta tests o build después de instalar las dependencias?

Preguntas frecuentes

¿Debo usar npm install en todos los pipelines?

No. Si el pipeline verifica un commit y tiene un lockfile válido, npm ci conserva mejor la frontera entre cambiar dependencias y comprobarlas.

¿npm ci siempre es más rápido?

No lo afirmo aquí. El resultado depende del proyecto, del runner, de la cache y de los scripts de ciclo de vida. La ventaja que este artículo demuestra es de contrato: el comando falla ante una diferencia en lugar de actualizar silenciosamente los archivos.

¿Qué hago después de un error de npm ci?

Lee el mensaje, compara los archivos, revisa versiones y opciones, reproduce en un fixture pequeño y corrige la causa en la rama. Cambia a npm install solo en el contexto donde la modificación del lockfile sea intencional y revisable.

Conclusión

La pregunta no es cuál comando hace que el pipeline termine. Es qué etapa tiene permiso para cambiar el árbol de dependencias. npm install pertenece al trabajo de modificar y revisar el lockfile. npm ci pertenece a la verificación automatizada de un estado ya aprobado. Mantener esa división hace que un error de CI sea una señal útil, no una invitación a mutar el commit durante el build.

Samuel Fajreldines es el autor responsable. La investigación comparó la documentación actual de npm para install y ci, la orientación de setup-node sobre lockfiles, resultados actuales en portugués, inglés y español y discusiones públicas usadas solamente para vocabulario operativo y modos de fallo.

El fixture local usó Node v25.5.0 y npm 11.8.0 el 26 de octubre de 2026. Demostró que npm ci falla cuando el manifiesto y el lockfile difieren y que npm install puede reparar el estado antes de una nueva verificación. No es un benchmark, no cubre todas las formas de workspace y no es una auditoría de seguridad.

La asistencia de IA apoyó la búsqueda de fuentes, la comparación, la organización, el borrador, la generación de la imagen, la localización y la revisión de consistencia. No sustituyó la ejecución del fixture ni añadió experiencia de proyecto que no se hubiera realizado.

Fuentes consultadas