What is Works on my machine?

Engineering culture and software practice

"Works on my machine" is the engineering phrase for software that behaves correctly on one developer's computer but fails somewhere else, such as a teammate's laptop, a test environment, or production. The phrase usually points to differences in environment, configuration, data, timing, permissions, or architecture. It can sound defensive, but at its best it is useful evidence: the machine is part of the bug.

What this means

Software never runs in the abstract. It runs on a particular operating system, with particular library versions, file paths, secrets, caches, background services, timezones, locales, permissions, and hardware. Two laptops that both seem "basically the same" can diverge in ways that matter a lot.

That is why this phrase has survived as both a joke and a warning. The joke is that every software team has heard it. The warning is that reproducibility is part of engineering, not a nice extra. If code only behaves on one machine, the machine is telling you something.

Sometimes the phrase is used badly, as if local success somehow settles the argument. Used properly, though, it is not the end of the conversation. It is the start of the comparison.

Why it matters

"Works on my machine" matters because it reveals a gap between code and environment. That gap is one of the most common sources of release pain, onboarding friction, inconsistent tests, and embarrassing production surprises. The code may be fine in one setup and fragile everywhere else because its real dependencies were never made explicit.

It matters culturally as well. The phrase can become defensive very quickly. One person hears it as, "your environment is wrong." Another hears it as, "I do not believe your bug report." Unless the team treats the phrase as data rather than attitude, trust drains out of the debugging process.

For leaders, it is a signal that local convenience and shared reproducibility have drifted apart. The fix is rarely just to lecture people to "test better." Teams need environment parity, version pinning, clear setup instructions, build consistency, realistic CI, and bug reports that capture machine facts. In other words, the phrase points toward a systems problem, not just an individual one.

How it works

Why the phrase keeps coming back

The reason is simple: developers naturally test first on the machine in front of them. Local feedback is fast, cheap, and essential. But that same speed creates local assumptions. A hidden environment variable is present. A database has hand edited test data. A package version is newer. A cache is warm. A filesystem is case insensitive. A laptop is x86 while production is ARM, or the other way round.

Continuous integration exists partly to catch exactly this kind of drift. Dev and production parity became a whole design principle for the same reason. Build systems at large companies aim for the same build result on every machine because anything less becomes expensive chaos at scale.

What usually causes the mismatch

The usual causes are familiar: dependency version drift, different backing services, undeclared secrets, stale local data, missing migrations, file permission differences, timezone and locale issues, architecture mismatches, and bugs that appear only under real concurrency or fuller datasets.

Sometimes the code itself is fine but the build is not reproducible. Sometimes the code relies on behaviour that a local service happens to provide but production does not. Sometimes everyone runs the same command but not on the same inputs. "Same code" is a much thinner guarantee than people think.

How teams reduce the problem

Teams reduce it by making environments describable and repeatable. They pin versions, script setup, commit configuration that is safe to commit, model infrastructure as code, use CI for every proposed change, and keep development, staging, and production as close as practical.

Containers and virtual machines help a great deal, but they are not magic. Containers share the host kernel and still depend on architecture and host level behaviour. CI helps enormously, but it cannot represent every production characteristic. The goal is not perfect sameness. The goal is to remove the easy, needless differences so that the remaining differences are visible and worth discussing.

Examples

A service passes locally because the developer's machine has a token in a forgotten shell profile and a database seeded months ago with neat, forgiving records. In CI, the token is absent and the test data is stricter. The code did not suddenly get worse. The local machine was carrying invisible assistance.

A front end builds on an Intel laptop and fails on an ARM based CI runner because a native dependency was only accidentally compatible in one environment. Everyone swears they ran the same command. They did. The command did not run on the same architecture.

A reporting job looks correct in local testing but disagrees with production after midnight. The local machine groups dates in one timezone. The server groups them in another. The line of code is identical. The clock around it is not.

Common misunderstandings

One misunderstanding is that "works on my machine" is always an excuse. It can be, but it can also be useful evidence. If something only succeeds in one environment, that difference is worth examining carefully.

Another is that containers have ended the problem. They help dramatically, but even containerised workflows still meet host kernels, architectures, mounted filesystems, network differences, and secret management issues.

People also assume CI alone is enough. CI is essential, but a green pipeline does not guarantee production behaviour under real scale, real traffic, or real data patterns.

A further misunderstanding is that this is mainly a junior engineer problem. It is not. Experienced teams accumulate local scripts, old caches, shell customisations, and special cases just as easily as anyone else.

Finally, some talk as if code and environment can be separated cleanly. In practice, the environment is often part of the program's real behaviour. Ignoring that does not make the dependency disappear.

Risks and boundaries

The phrase becomes harmful when it stops the conversation. If a developer says it and means, "therefore the problem is yours," the team is already in trouble. The healthy follow up is, "good, now let's compare what is different."

There is also a limit to parity. Not every production factor can or should be cloned locally. Live scale, real user traffic, third party rate limits, and messy long lived data all resist neat replication. Chasing perfect sameness can waste effort.

The right boundary is practical reproducibility. Remove drift where you can. Record the rest explicitly. If the difference matters, make it visible in tooling, docs, or CI. If it cannot be mirrored locally, acknowledge that and test in a more representative place.

The worst version of "works on my machine" is defensive folklore. The best version is an empirical clue that points toward a specific comparison.

What to do next

If your team keeps running into this pattern, standardise the basics. One command should build the project. One command should run the main tests. Dependency versions should be pinned. Setup should live in version control, not in someone's memory or dotfiles.

Push for environment descriptions as code where practical. That may mean container definitions, virtual machine configs, package manifests, scripts, seed data, or CI configuration that mirrors local development closely enough to be meaningful.

Improve bug reports too. Ask for operating system, architecture, app version, branch, dependency versions, relevant environment variables, recent changes, and reproduction steps. When people report problems with that context, "works on my machine" becomes easier to translate into a concrete diff.

Most of all, treat reproducibility as part of product quality. It affects delivery speed, incident rate, onboarding, and even how credible engineering looks to the rest of the business.

FAQs

Is "works on my machine" ever useful?

Yes. It tells you the failure depends on something outside the visible code path, such as environment, data, timing, configuration, or architecture. That is valuable debugging information.

Do containers eliminate the problem?

They reduce a large chunk of it, but not all of it. Host behaviour, architecture, secrets, mounted files, and external services can still differ in ways that matter.

What should I compare first?

Start with the basics: operating system, architecture, branch, dependency versions, environment variables, database state, recent migrations, and the exact command that was run.

Why does CI catch this so often?

Because CI runs the code in a cleaner, more standardised environment. Hidden local assumptions that pass quietly on one laptop often fail immediately there.

Is this mainly about development versus production?

Not only. It also happens between two developer machines, between local and CI, between two CI runners, and between one region and another if configuration or infrastructure differs.

How does this relate to reproducible builds?

Reproducible builds aim for the same build result from the same inputs on any machine. That principle attacks one core source of "works on my machine" pain at the build level.

Sources

  • An Introduction to DevOps (Carnegie Mellon Software Engineering Institute). Practical explanation of the phrase and how canonical development environments reduce local drift.