# Can I Use a Makefile to Manage Dotfiles? A Deep Dive into Ivan Smirnov’s Dotfiles Repository

> Learn if Makefiles can manage dotfiles. Explore the issmirnov/dotfiles repository and discover why Bash and dotbot offer superior cross-platform compatibility.

- Repository: [Ivan Smirnov/dotfiles](https://github.com/issmirnov/dotfiles)
- Tags: deep-dive
- Published: 2026-03-04

---

**Yes, you can use a Makefile as a thin wrapper around existing scripts, but the issmirnov/dotfiles repository intentionally uses a Bash-driven dotbot workflow rather than Make for cross-platform compatibility.**

The dotfiles community often debates whether Make is the right tool for managing symlinks and system configuration. In the `issmirnov/dotfiles` repository, the author deliberately avoids a top-level `Makefile`, opting instead for a flexible, OS-aware shell script architecture centered on dotbot. This approach provides declarative configuration management through YAML files while remaining portable across Ubuntu and macOS systems.

## Why There Is No Built-In Makefile

The repository ships without a root-level `Makefile` because the installation logic is already encapsulated in portable shell scripts. The main `./install` script handles OS detection, selects appropriate YAML configurations, and delegates heavy lifting to dotbot.

The decision to avoid Make stems from four architectural choices evident in the source code:

- **Installation Orchestration**: The `./install` script initializes the dotbot submodule and processes configuration files like [`default.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/default.conf.yaml). A Makefile would simply call this script anyway, adding an unnecessary abstraction layer.
- **OS-Specific Branching**: The repository uses separate configuration files ([`ubuntu.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/ubuntu.conf.yaml), [`osx.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/osx.conf.yaml)) selected dynamically based on the `$OSTYPE` environment variable. This conditional logic is handled within the Bash script rather than Makefile conditionals.
- **Utility Provisioning**: The [`util/install-utils.sh`](https://github.com/issmirnov/dotfiles/blob/main/util/install-utils.sh) script detects the operating system and package manager to fetch binaries like `fzf`, `bat`, and `zoxide`. Porting these checks into Make syntax would duplicate existing POSIX-compliant logic.
- **Submodule Builds**: The only Make usage appears in [`provision/i3.sh`](https://github.com/issmirnov/dotfiles/blob/main/provision/i3.sh), which runs `make clean all` inside the `i3blocks` submodule directory. This is third-party build logic, not the repository's own dotfile management system.

## Understanding the Existing Script-Driven Architecture

Before adding a Makefile wrapper, understand how the repository currently manages dotfiles through three core components.

### The Bootstrap Process (install)

The entry point `./install` is a Bash wrapper located in the repository root. It clones the dotbot submodule if missing, selects the appropriate configuration file for the current OS (e.g., [`ubuntu.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/ubuntu.conf.yaml) or [`osx.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/osx.conf.yaml)), and executes the installation. This script serves as the primary interface for new machine setup and handles the complexity of cross-platform initialization.

### Configuration Management (YAML Files)

Dotbot configurations like [`default.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/default.conf.yaml) define symlink mappings and post-install shell commands using a declarative schema. These YAML files separate the "what" (which files to link) from the "how" (the installation logic), making the system more maintainable than Make targets for file operations. The configuration specifies source paths in the repository and target paths in `$HOME`, letting dotbot handle idempotent symlink creation.

### Cross-Platform Utility Installation

The [`util/install-utils.sh`](https://github.com/issmirnov/dotfiles/blob/main/util/install-utils.sh) script provides POSIX-compliant installation of auxiliary CLI tools. It detects package managers (`apt`, `brew`, etc.) and installs utilities like `cheat` and `zoxide` without requiring Makefile conditionals or OS-specific targets. This script executes direct package manager commands rather than relying on Make's build semantics.

### Third-Party Build Dependencies

In [`provision/i3.sh`](https://github.com/issmirnov/dotfiles/blob/main/provision/i3.sh), the script compiles `i3blocks` from source using its own Makefile via `make clean all`. This demonstrates that the repository does use Make, but only for building external dependencies inside submodules, not for managing the dotfiles themselves. The script also handles compiling `rofi` and other X11 utilities that require native compilation.

## Creating a Makefile Wrapper

If you prefer typing `make install` over `./install`, you can add a thin Makefile that delegates to the existing scripts. This approach preserves the repository's core logic while adding convenient targets for common workflows.

```make

# Makefile – thin wrapper around the existing dotfiles scripts

.PHONY: all
all: install

# Run the main install script (dotbot bootstrap)

.PHONY: install
install:
	./install

# Install the helper utilities (fzf, bat, etc.)

.PHONY: utils
utils:
	./util/install-utils.sh

# Set up i3 (includes a make call inside the i3blocks submodule)

.PHONY: i3
i3:
	./provision/i3.sh

# Clean up generated symlinks (dotbot clean)

.PHONY: clean
clean:
	./dotbot/bin/dotbot -d . -c "default.conf.yaml" -p clean

# Update submodules and re-run installation

.PHONY: update
update:
	git submodule update --init --recursive
	$(MAKE) install

```

Each target maps directly to existing functionality:

- `make install` executes the official `./install` script that drives dotbot.
- `make utils` runs the utility installer at [`util/install-utils.sh`](https://github.com/issmirnov/dotfiles/blob/main/util/install-utils.sh) to fetch modern CLI replacements.
- `make i3` triggers the provisioning script that builds `i3blocks` using its internal Makefile.
- `make clean` invokes dotbot's clean plugin via `./dotbot/bin/dotbot` to remove all symlinks defined in [`default.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/default.conf.yaml).
- `make update` synchronizes git submodules before reinstalling, ensuring dotbot and other dependencies remain current.

Place this file in the repository root to use alongside the existing workflow without modifying core files or interfering with the script-driven architecture.

## Summary

- The `issmirnov/dotfiles` repository uses a **Bash-driven dotbot workflow** rather than Make for cross-platform compatibility.
- The `./install` script handles OS detection via `$OSTYPE` and delegates to YAML configuration files like [`default.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/default.conf.yaml) and [`ubuntu.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/ubuntu.conf.yaml).
- Utility management in [`util/install-utils.sh`](https://github.com/issmirnov/dotfiles/blob/main/util/install-utils.sh) provides POSIX-compliant package installation that would be difficult to replicate in Make syntax.
- You can add a **Makefile as a thin wrapper** around existing scripts without changing the repository's underlying architecture or dotbot configuration.
- The only Make usage in the repository occurs in [`provision/i3.sh`](https://github.com/issmirnov/dotfiles/blob/main/provision/i3.sh) for compiling third-party tools like `i3blocks` via `make clean all`.

## Frequently Asked Questions

### Does issmirnov/dotfiles include a Makefile by default?

No, the repository does not ship with a top-level Makefile. The installation process relies on the `./install` Bash script, which configures dotbot using YAML files in the repository root. You can create a custom Makefile that wraps these existing scripts if you prefer Make's command interface, but it remains optional.

### Why does the repository use dotbot instead of Make for managing symlinks?

Dotbot provides a declarative YAML configuration format that separates file linking logic from OS-specific implementation details. The [`default.conf.yaml`](https://github.com/issmirnov/dotfiles/blob/main/default.conf.yaml) file defines symlinks and shell commands without requiring Makefile syntax or complex target conditionals, making the configuration more readable and maintainable across different operating systems.

### Can I still use Make targets to install specific components like i3?

Yes, you can write a Makefile that delegates to existing provisioning scripts. The [`provision/i3.sh`](https://github.com/issmirnov/dotfiles/blob/main/provision/i3.sh) script already uses `make clean all` internally to build the `i3blocks` submodule from source, so adding a Make wrapper simply provides a convenient entry point without duplicating build logic or interfering with the submodule's own build system.

### How do I clean up symlinks if I don't use Make?

Run `./dotbot/bin/dotbot -d . -c "default.conf.yaml" -p clean` directly from the repository root. This invokes dotbot's clean plugin to remove all symlinks created during installation, equivalent to the `make clean` target shown in wrapper examples. This command works on any system where dotbot is initialized, regardless of whether you use a Makefile.