DEV Community

Cover image for Avoiding Production Disasters with npm ci: The Key to Stable Deployments
Pranav Kale
Pranav Kale

Posted on • Edited on

Avoiding Production Disasters with npm ci: The Key to Stable Deployments

Introduction

Managing dependencies in JavaScript projects is a critical task, and npm (Node Package Manager) provides robust tools to handle versioning effectively. Developers often face issues with inconsistent dependencies across environments, leading to unexpected bugs and compatibility problems. This is where npm versioning and the npm ci command come into play.

In this blog, we will explore npm versioning, the significance of package.json and package-lock.json, and how npm ci ensures consistent installations. We'll also discuss a real-world scenario where npm ci saved the day.

Understanding npm Versioning

package.json and Semantic Versioning (SemVer)

Every Node.js project includes a package.json file, which lists dependencies along with their version numbers. These versions follow Semantic Versioning (SemVer), which consists of three numbers:

MAJOR.MINOR.PATCH
Enter fullscreen mode Exit fullscreen mode
  • MAJOR : Incompatible changes (e.g., breaking changes).
  • MINOR : Backward-compatible new features.
  • PATCH : Backward-compatible bug fixes.

Version Ranges in package.json

In package.json, dependency versions can be defined using different symbols:

  • Tilde (~): Accepts only PATCH updates.
  • Caret (^): Accepts MINOR and PATCH updates.
  • Fixed version: Ensures an exact version.

While these flexible ranges help in staying up to date, they can sometimes introduce inconsistencies between development and production environments.

package-lock.json: Locking Dependencies

The package-lock.json file ensures exact versions of dependencies and their sub-dependencies are locked. This prevents issues where different team members or CI/CD pipelines might install slightly different versions of packages due to SemVer rules.

What is npm ci, and Why is it Important?

  • npm install: Installs dependencies based on package.json, potentially updating package-lock.json.

  • npm ci: Stands for "clean install." It removes node_modules and installs exact versions from package-lock.json, ensuring consistency across environments.

Real-World Scenario Where npm ci Helped

Problem: Production Outage Due to Dependency Mismatch

A team was maintaining a large enterprise web application that relied heavily on dynamic data tables using AG Grid. Their package.json included the following dependencies:

{
  "dependencies": {
    "ag-grid-angular": "^28.2.0",
    "ag-grid-community": "^28.2.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

During deployment, npm install was used instead of npm ci, which resulted in a minor version upgrade to AG Grid 28.2.3 in production. However, this update introduced a breaking change in how grid rendering was handled, causing all tables across the application to break. As a result:

  1. Users couldn't view or interact with tabular data.
  2. Critical business workflows were disrupted.
  3. Customer support received numerous complaints, impacting the company’s reputation.

Solution: Implementing npm ci

To prevent such issues in the future, the team switched to npm ci in their CI/CD pipeline. This ensured that:

  1. Only exact versions from package-lock.json were installed, preventing unexpected upgrades.
  2. Production and development environments used identical dependencies, ensuring consistency.
  3. Builds were predictable, reducing deployment risks.
  4. Deployment times improved, as npm ci performs a clean install more efficiently than npm install.

Outcome

After implementing npm ci, the team ensured that future deployments used only tested dependency versions, preventing surprise breaking changes. The production environment remained stable, and the AG Grid tables continued functioning as expected.

Conclusion

Understanding npm versioning and leveraging npm ci can significantly improve dependency management. While npm install is useful for development, npm ci is the best choice for CI/CD pipelines, ensuring strict version control and eliminating unpredictable bugs.

By using npm ci, teams can achieve reliable builds, faster deployments, and consistent environments, ultimately saving time and avoiding production issues.

Top comments (1)

Collapse
 
pavelee profile image
Paweł Ciosek

Thanks!