Evan Travers’ devenv workflow exposes a quiet tension in modern software teams, the need for reproducible local infrastructure without turning personal tooling into a team mandate.

Thesis
Evan Travers’ post, “But Our Devenv Is In Another Repo”, is not merely a note about arranging files around devenv and Nix. It is a small case study in one of the more persistent problems in software work: the development environment is part of the system, but it is not always politically, socially, or organizationally acceptable to treat it as part of the project.
The core argument is pragmatic and revealing. A reproducible environment is most valuable when it is versioned, shared, and close to the code it supports, yet consultants, contractors, and tool-conscious developers often cannot assume that the rest of a team wants to adopt the same machinery. Travers’ workaround, keeping devenv configuration in a sibling “configuration repo” and importing it into each real project repo, is an attempt to preserve the virtues of infrastructure-as-code while respecting the fact that tooling choices are never purely technical.
Key Arguments
The first argument is that devenv succeeds because it embraces Nix rather than hiding it completely. Travers contrasts devenv with other Nix-based development environment tools that try to offer the benefits of Nix without asking users to write Nix. That design goal is understandable, since Nix has a reputation for being powerful, strange, and syntactically unfamiliar. Yet Travers suggests that hiding the underlying model can become a liability, because serious development environments eventually need composition, conditionals, package control, service definitions, language-specific tuning, and project-specific exceptions.
In the example, the configuration repo defines shared packages, environment variables, language settings, host mappings, certificates, Node.js versions, LSP support, and aws-vault integration. This is precisely the kind of configuration that tends to begin life as a few shell exports in a README and then gradually becomes a distributed oral tradition. By putting it in devenv, Travers makes the environment declarative enough to reason about, repeat, and revise.
The second argument is that putting development tooling directly in the project repo is not always socially neutral. If the team has already standardized on NVM, Docker Compose, Homebrew, ASDF, Makefiles, manual setup notes, or nothing at all, committing devenv files may look like an unsolicited architectural decision. For a consultant, that matters. The repo is not merely a filesystem location, it is a shared governance boundary.
That is why the sibling configuration repo is interesting. It allows the developer to keep the environment under version control without forcing every collaborator to see or accept it. The project repo contains only a minimal devenv shim, with local files excluded from Git, while the substantial configuration lives next door and is imported through devenv.yaml. This turns the environment into a private overlay: close enough to the project to be useful, distant enough not to become a team decision.
The third argument is that reproducibility and changeability can come into tension. Travers reports that the setup works reliably, but that .devenv cache behavior can make updates in the configuration repo fail to appear until local cache directories are removed. That detail matters because cache invalidation is not a side issue in reproducible systems. It is part of their epistemology. If a tool says, “this is your environment,” the developer needs to know whether that environment reflects the source files, a lock file, a cache directory, an imported path, or some combination of all three.
Implications
This pattern points toward a more nuanced model of developer experience. The usual binary is “team standard” versus “personal setup,” but real projects often need something between those poles. A personal environment can still be disciplined. It can still be versioned. It can still encode project knowledge. It can still reduce onboarding friction for the person maintaining it, even if it is not yet institutionalized.
For teams working across several repositories, this becomes especially important. Travers mentions projects with four or more repos, shared environment variables across only some of them, separate languages, and constant motion. In that kind of system, the local development environment is not just a convenience layer. It becomes a map of interdependence. Which repo needs which Node version. Which service needs certificates. Which project should resolve a fake local hostname. Which tools need AWS credentials. Which editor integrations are expected to work.
A configuration repo, in this sense, becomes a personal control plane for a fragmented system. It does not solve every coordination problem, but it gives the developer a place to express the shape of the work as they actually experience it. That is a philosophical shift from “the repo contains the app” to “the working system includes the constellation around the app.”
There is also a lesson here for tools like devenv, direnv, and Nix flakes. Reproducibility tools are often judged by whether they can build the same thing twice, but developers also need to understand how those tools respond to partial change. Imported local paths, profiles, shells, secrets, caches, and generated directories all participate in the user’s mental model. When that model is unclear, the tool may still be correct, but it feels stubborn.
The appeal of devenv’s newer features, including its secrets support in the devenv documentation, is that they pull more of the environment into an explicit, inspectable system. That matters because local development is full of ambiguous state: shell history, .envrc files, ignored config, generated caches, local certificates, and credentials. The more of that state can be named and scoped, the less it depends on memory.
Counter-Perspectives
The strongest counterargument is that a separate configuration repo may be too clever for its own good. It introduces another dependency, another path assumption, and another layer of indirection. A future maintainer, or even the same developer three months later, may need to reconstruct why a project’s local shell depends on a sibling directory with profiles named after repos. The workaround respects team boundaries, but it also creates a private architecture.
A second counterargument is that uncommitted project-local devenv files weaken one of the main promises of devenv. If the real project repo does not contain the source of truth, then the environment is reproducible only for the person who knows about the configuration repo. That may be acceptable for a contractor’s personal workflow, but it is less compelling as a team practice. At some point, if the environment captures important project knowledge, the team may be better served by discussing whether that knowledge belongs in the project itself.
A third counterargument concerns cache behavior. If updating the configuration repo requires deleting .devenv, the workflow has a hidden maintenance cost. It may still be better than manual setup, but the developer now has to remember a ritual whenever imported configuration changes do not take effect. In systems meant to reduce ambient complexity, such rituals are warning signs.
The post’s real value is that it does not pretend the trade-off has been solved. Travers presents a working arrangement, names the friction, and leaves the question open. That humility is useful. Development environments are not only technical artifacts, they are agreements about how much of the work should be made explicit, who has to carry that explicitness, and where the boundary lies between personal craft and shared infrastructure.

Comments
Please log in or register to join the discussion