Managing Dotfiles with Make
Posted4 months agoActive3 months ago
matheusmoreira.comTechstory
calmmixed
Debate
60/100
Dotfiles ManagementMakefilesConfiguration Management
Key topics
Dotfiles Management
Makefiles
Configuration Management
The article discusses using Make to manage dotfiles, sparking a discussion on various approaches to dotfiles management and the trade-offs between different tools and methods.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
4d
Peak period
23
84-96h
Avg / period
8
Comment distribution48 data points
Loading chart...
Based on 48 loaded comments
Key moments
- 01Story posted
Sep 26, 2025 at 2:15 AM EDT
4 months ago
Step 01 - 02First comment
Sep 29, 2025 at 8:26 PM EDT
4d after posting
Step 02 - 03Peak activity
23 comments in 84-96h
Hottest window of the conversation
Step 03 - 04Latest activity
Oct 3, 2025 at 9:21 AM EDT
3 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
ID: 45383284Type: storyLast synced: 11/20/2025, 5:36:19 PM
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
It also has the downside that you have to install and set up chezmoi first, and it isn't included in the debian or ubuntu repos.
I also tend to put a Makefile into the root of any repo I work in (ignored via .git/info/exclude), so that shell commands relevant to my workflow can accumulate under that Makefile. I've been doing this for at least 10 years and love it. Most repos have some sort of a cli interface, but that doesn't mean that they're any good. Make is nice way to wrap all of them, and to standardize on at least the build/test/run commands across many disparate repos.
Here's an example of one of those from a long-abandoned project: https://gist.github.com/staticshock/0e88a3232038d14a2817e105...
Perhaps I want to hold it to my own standard for tooling, not the team’s.
Perhaps I want to write it in a language that the team doesn’t really embrace.
I might not think it’s worth anyone’s time to code review changes I make to my own tools.
I might want to do something dumb like bake an API key into the tool.
Maybe the project already has a similar tool, and I don’t want to explain why I am wrapping/ignoring it.
In short: sometimes the cost to collaborate on idiosyncratic tools is just higher than I’m willing to pay.
I just want to hack together something that works for my use case. If I can share that with the wider team, that is superb. But I really don't enjoy my hacky utils being subject to tedious code review scrutiny they don't deserve.
To be clear, I _do_ add utils that I think will be useful to the common repo, subject to review, and mostly they will be merged. But if it gets painful, I just retract the PR and keep it locally.
What an extraordinary amount of unnecessary effort that would be. My workflow does not belong to the repo, it belongs to me. The only thing that belongs in the repo is all the shared workflows (or the elements they comprise.)
*
And if I need to add something, I just "git add -f ...". Works surprisingly well. Combines well with git-secret for things like SSH keys, certificates and API keys.
https://www.atlassian.com/git/tutorials/dotfiles
it's simultaneously awesome but "can I really recommend this to <colleague>?"
For example, here's a snippet pulled from my dotfiles that does this for multiple dotfiles at once:
At the same time it often feels like a veneer of control, like you can control exactly where to place the door, but what's in the messy room (like emacs profiles if you do that) might be hidden behind the very nice and solid door.
It's like in python projects I lock python3 and uv, and beyond that it's wild west. Still beats everything else, still feels a bit incomplete, and still feels somewhat unresolvable.
It depends on buy-in from the tool so it’s not a panacea but it works for my use cases at least. I also don’t like to switch config for every change and it turns out I rarely have to.
Nix is definitely The Way to solve this problem, but I wouldn’t recommend it if the only thing you’ll ever use it for is home-manager. Once you’ve paid the investment, though… I never want to rsync a dotfile ever again in my life.
I really appreciate and use nixpkgs+nix-darwin as well as NixOS and flakes and per-project nix-shell/nix develop through and through; even then, Home Manager is a bridge too far for me.
One of the features of my dotfiles setup is that it has zero dependencies (beyond a POSIX shell).
This Makefile is anything but simple. It uses advanced features that are meant for complicated situations, just to create a few symlinks. The same symlinks, every time. And if you introduce a new dotfile to the repo, you have to update the Makefile too.
It also makes no use of the main feature of make(1) - to track files for changes, and update them.
For demonstration, here is the same functionality, in sh(1):
Doesn't use advanced features, shorter, and you don't need to update the script for new dotfiles. And more "ubiquitous" than GNU make.This makefile does look simple to me, although it is not easy; but TFA never claimed it was supposed to be "easy".
The shell you mentioned is not in any way "simpler" nor even "easier". The same thing can be done with bash substitutions and loops (all supported by zsh), and someone would argue that it'd be simpler by virtue of not suffering e.g gnu vs bsd vs posix sed nor needing xargs; also, pipefail and such.
Also it doesn't do "the same thing": you have to be at a specific pwd and not in any subdir + you can't do a subset (e.g "make git")
Note I'm not saying it's better or worse.
I really like the article as it showcased a few advanced make features in a concrete and limited use case (symlinks). The result is simple to use and maintain.
TFA> Another reason to use it is this turned out to be a surprisingly easy task.
I'm very prone to being entranced by the eerily lisp-like nature of GNU Make. Got side tracked in one of my projects trying to recreate GNU autoconf inside it. That was the day I finally understood what autoconf was even doing.
The real point of make is it's a declarative build system. You just tell it to make and it will do what needs to be done by figuring out dependencies and rebuilds.
A Makefile with tasks that just run external scripts is much easier to find than the scripts directly. Add some help texts and it’s a great DevEx multiplier.
With a Makefile I can generally just run `make` or `make <tab>` to have a feel for what's available. It's right there on my terminal, which is usually the first thing I interact with when I open a repository. If enough of the engineers use it, it stays up-to-date as it gets fixed and updated along with any other changes.
Documentation OTOH has a tendency to be forgotten and left for dead. IME this is especially true for internal documentation, and the closest to the code the docs are, the less attention they receive - since higher level documentation is more likely to be consumed by people outside of the team.
With a README, I need to:
* remember to read it * trust that it will have the information * trust that the information is up-to-date * finally, figure out paths to scripts, arguments and/or copy-paste commands
Not at all. The rules are generic. I can give make any path inside my home directory and it will try to match it against an equivalent file in the repository.
I only need to update the makefile if I want easy to use phony targets. These phony targets in turn simply depend on the paths to the real files which activate the generic rules I described in the article.It looks complicated because I used functions to compute all these paths from the items in the repository. Here's what the final result looks like:
I could have used any of those paths and it would have worked. The phony targets are nice but not strictly needed.The bulk of the makefile is dealing with environment variables such as XDG_*_HOME and GNUPGHOME variables which affect where the links are supposed to end up.
I have a simple bash script that does something similar: https://erock-git-dotfiles.pgs.sh/tree/main/item/dotfiles.sh...
It works fine - most of my time is still spent in configuring Neovim ^^
I ended up writing a Go CLI to symlink my dotfiles. It's probably 10x more lines of code, but it uses a "plan, then execute" pattern, similar to Terraform that I find easier to test and clearer to use too. And it's a single binary so it's easy to install on Windows too.
Here is mine: https://github.com/balazs4/dotfiles/blob/canary/makefile
I am pretty happy about it nowadays; it works for me.
Cheers
I also suggest putting the complete final version of the Makefile at then end, so I can copy it.
Regards,
I typically checkout the dotfiles repo to a personal project folder on every new OS build and then run the installer to get all my configs in place.
- [1] https://shaky.sh/simple-dotfiles/ - [2] https://gitlab.com/jgonyea/dotfiles