The tragedy of running an old Node project

Fragility of Older Node Projects

  • Many commenters report that Node projects “rot” quickly: even a few months’ or years’ gap can make them hard or impossible to build.
  • Breakage often appears when trying to run old code on a newer Node version, or when dependencies have silently changed or vanished.
  • Some argue two hours of work after four years is acceptable; others say that in other stacks they routinely revive 10–20‑year‑old code in minutes.

Native Extensions and node-gyp

  • node-gyp and native addons (C/C++ bindings) are repeatedly cited as the main source of pain: toolchains change, Python 2 vs 3 issues, missing system libs, architecture mismatches.
  • Advice: avoid packages that depend on node-gyp unless absolutely necessary (e.g., password hashing, image processing). Prefer pure JS, or offload such concerns to external services.

Comparisons with Other Ecosystems

  • Several ecosystems are described as more stable for old projects: Go, Java, C/C++, C#, Perl, PHP, Common Lisp, R, Tcl; others (Python, Ruby, Android, React Native) are reported to have similar or worse bitrot.
  • Some note that problems correlate strongly with deep transitive dependency trees and native extensions, not just language choice.
  • Debate exists: some say Go/Java/C# “just work” for decade‑old code; others recount hard upgrades (Java 8→9, Spring, Gradle, Xamarin, old Go without modules).

Dependency & Environment Management Tactics

  • Recommended practices:
    • Pin Node version (engines in package.json, .nvmrc, asdf/mise, devShells).
    • Commit lockfiles and, when possible, vendor dependencies.
    • Use Docker or similar to freeze OS, toolchain, and Node version.
    • Run CI to ensure builds stay reproducible.
  • Lockfiles and narrow version ranges improve reproducibility but can over‑constrain environments; some argue for libraries that support wider version ranges.

Cultural and Architectural Critiques

  • Several see Node/npm issues as cultural: speed and churn, huge dependency graphs, frequent framework rewrites, loose attitudes about stability and semver.
  • Others stress this is a general modern‑software problem: maintainers lack incentives to support old versions, and any stack with many moving parts will decay.

Alternatives and Mitigations

  • Suggestions include:
    • Buildless or low‑tooling approaches (vanilla JS, HTMX, Alpine, simple static site generators, Hugo).
    • Choosing ecosystems with strong backward compatibility and big standard libraries.
    • Keeping dependencies minimal and treating them like own code.