Works on My Machine
"Works on my machine" code depends on undeclared local state and fails everywhere else. Use containers, pinned dependencies, and environment parity so local, CI, and production environments match exactly.
"Works on my machine" is the classic developer refrain when code runs locally but fails in CI, staging, or production. The phrase has become shorthand for an entire class of problems: software that depends on undeclared, environment-specific state rather than on explicit, portable configuration.
The code is not actually correct; it merely happens to work given one machine's accumulated, undocumented setup.
Why It Happens
Developers' machines accumulate tools, libraries, environment variables, and globally installed packages over months of work. Code unconsciously starts depending on this hidden context: a globally installed CLI, a specific runtime version, a file path that exists only on the developer's disk, or a service running on localhost. None of it is declared, so it travels nowhere.
The gap is invisible until the code runs somewhere clean. Without environment parity, local success is no signal of portability.
Why It Hurts
The failure surfaces late, after handoff, when it is most expensive to diagnose. Teammates waste hours reproducing setups. Integration and deployment stall on issues that have nothing to do with the actual feature. Trust erodes between developers and operators. The deeper cost is non-reproducibility: if it only works on one machine, it does not really work at all.
Warning Signs
- Tests pass locally but fail in CI for environmental reasons.
- Dependencies are installed globally and never pinned or declared.
- The code contains hardcoded absolute paths or assumed services.
- Required environment variables are not documented.
Better Alternatives
Use containers (Docker) or dev containers so every developer, CI runner, and production host shares an identical, declared environment. Pin all dependencies explicitly with lockfiles. Externalize configuration through environment variables with documented defaults. Strive for environment parity so local, CI, and production differ as little as possible, following twelve-factor principles.
How to Refactor Out of It
Reproduce the failure in a clean environment to surface every hidden dependency. Declare each one: add it to a lockfile, a Dockerfile, or a documented config. Replace hardcoded paths and assumed services with configurable values. Run the build and tests inside the same containerized environment locally and in CI so the two can never diverge silently again.