Productive on a New Machine Before the Coffee Gets Cold

Learn how dotfiles, version managers, containers, and secret management make a new development machine reproducible in minutes.

Gabriel's avatar
Gabriel
Productive on a New Machine Before the Coffee Gets Cold

You switch laptops, reinstall your system, or join a new team. And there go two days reinstalling things, hunting for that alias you swore you would never forget, and discovering at the worst possible moment that the project runs on Node 18 while you installed 22. Reproducibility is not a luxury for people with OCD. It is what separates a developer who gets productive again in minutes from one who needs days.

A reproducible development environment: a new machine becoming ready quickly from versioned files.
A reproducible development environment: a new machine becoming ready quickly from versioned files.

The problem is not the machine—it is your memory

Your development environment is knowledge that lives in your head and evaporates. Every export, every brew install, and every tweak to .bashrc is a decision you will not remember six months from now. The goal is simple: turn that tacit knowledge into versioned files. If it is in a repository, it survives a system reinstall.

Dotfiles: your environment in a repository

Your configuration files—.zshrc, .gitconfig, .vimrc, aliases—are your dotfiles. Put them in a Git repository and you have your entire shell under version control. The cleanest technique is a bare repo pointing to your home directory, but to get started, a ~/dotfiles folder with a script that creates symlinks is enough:

bash ln -sf ~/dotfiles/zshrc ~/.zshrc ln -sf ~/dotfiles/gitconfig ~/.gitconfig

New machine? Run git clone, execute the script, and your terminal is the same as always. Tools such as chezmoi and stow automate this and also handle differences between machines—work and personal, for example. Just do not give in to the temptation to version secrets alongside them—we will get to that.

Version managers: stop fighting versions

Installing Node, Python, or Ruby directly on the system is asking for trouble. Every project wants a different version, and global sudo installs turn into a minefield. Version managers solve this: nvm for Node, pyenv for Python, and rbenv for Ruby.

Even better, asdf—or mise, its faster successor—unifies everything in one tool. You declare the versions in a .tool-versions file at the project root:

nodejs 20.11.0 python 3.12.2

Enter the directory and the environment automatically switches to the right versions. Commit this file and the entire team runs the same runtime—no more “works on my machine.”

Containers and devcontainers: the machine is disposable

A version manager handles languages. But what about Postgres, Redis, or that annoying system library that is difficult to install? That is where containers come in. A docker-compose.yml file in the repository starts the database and dependencies with one command, giving everyone the same setup without polluting their machines.

Devcontainers go further: you describe the entire environment in a .devcontainer/devcontainer.json, and VS Code—or GitHub Codespaces—builds a container with everything ready: extensions, tools, and versions. Onboarding becomes “open the project and wait for the build.” The physical machine becomes just a thin client; the environment lives in the repository.

Secrets and .env: where most people get burned

Rule number one: .env never goes into Git. Add .env to .gitignore before the first commit, not afterward—a secret that has already entered the history remains there even if you delete the file.

The serious pattern is to commit a .env.example with the keys but without the values:

DATABASE_URL= API_KEY=

That way, the next developer knows what needs to be filled in without you leaking anything. For real secrets, use a manager—1Password CLI, doppler, or sops—that injects the values at runtime without leaving them on disk. And if a secret leaked into the history, rotate the key. Deleting the commit does not undo the leak.

The real test: build everything from scratch

The proof that your environment is reproducible is brutally simple: take a clean machine—or a container—and build everything by following only what is in the repository. If you get stuck at any step, that step is knowledge that still lives only in your head—document or automate it.

Start small: today, move your dotfiles to a repo. Tomorrow, adopt a version manager. Next week, write the docker-compose file. You do not need the perfect setup—you need one you can rebuild. Because the next new machine is coming, and the difference between hot coffee and cold coffee is how much you automated beforehand.

Did you enjoy this article?

Share it with your friends and help spread knowledge!