Managing Dotfiles with Yolk

Published: Jan 27, 2026 · Updated: Feb 9, 2026

guidelinux

I found yolk when searching for an easy way to manage and template my configuration files. I had been using GNU Stow beforehand, but it lacks a convenient templating method.

Apart from the yolk documentation itself, I couldn’t find many resources about how to use it. I also haven’t seen it mentioned in many online discussions or lists of similar tools. This is a quickstart guide for replicating my yolk setup and getting started with configuration templating. If you’re interested, you can read about how I previously managed configuration files with Stow. Otherwise, skip straight to seeing how I use yolk.

Background & Problem

I didn’t have a need for managing configuration files at all until relatively recently. Most of the programs I used had convenient ways to import, export, set, and sometimes autoconfigure or sync your options. This changed when I took a class called Secure Digital Technologies during the early stages of my degree at Ferris State University. After this point I would have to increasingly rely on Linux programs (terminal or otherwise) for academic and work purposes. Many of these applications require manual configuration by editing files directly or writing them yourself.

Writing and editing configuration files isn’t normally difficult, but it can quickly become a mess as more programs are installed. It becomes harder to manage and version control more files, and they will often become dispersed across your disk(s) over time. Some applications might expect files in ~/.config/, while others might want them sitting loosely in the home folder.

File management challenges started to hinder my ability to experiment - which was part of the reason I began using Linux in the first place. Besides needing it for work and learning purposes, I also like having the ability to fully customize every aspect of the system. Manually handling problems with configuration file management would be unwieldy, impractical, error-prone, and time-consuming. A smarter solution is necessary. I needed a way to centralize and version control all of my important configuration files. Ideally, it should also be easy to make per-device changes.

Stow

I learned this method from a guide linked on Stow’s homepage. It wasn’t a perfect solution for my needs, but it worked well enough for a long while. Some of the notes I made for myself about using Stow are included below.

Create a .dotfiles/ directory to use as a central location for managing your configurations. Regardless of what your programs call for, you can organize your configurations in (more or less) whichever way you like within this directory at the top level. Beyond that, you should mimic the structure that your programs expect.

It’s also a good idea to start tracking changes (remember to make regular commits with meaningful messages):

git init
git add .
git commit -m 'initial commit'

To stow something is to create symbolic links using the stow command:

stow --dotfiles -vt <target-dir> <package>

To unstow something is to remove the symbolic links - the reverse of stowing:

stow --dotfiles -vt <target-dir> -D <package>

Top-level folders in your .dotfiles/ directory are treated as packages by the stow command. By default, it will target the parent directory and create symlinks for your Stow package(s) there. If necessary, use the -n option to simulate changes to the filesystem. This can be a useful way to check your work when combined with different verbosity levels.

The target directory will likely be your home directory when managing configuration files. As an example, the command to enable the vim configuration is:

stow --dotfiles -vt ~ vim

When this command is run, stow will look inside the in the .dotfiles/vim/ directory and see the dot-vim/ folder. It then creates a .vim/ symlink in ~/.

You don’t have to follow the dot- naming convention, but it avoids the problem of having a package directory filled with hidden files. Make sure you use the --dotfiles option if you decide to do this.

Shortcomings

This old method works fine when you only need one version of every configuration file, but what about when you need different configs for different machines? After all, I did mention that per-device changes sould be easy. I could change my workflow to use multiple Git branches, but I honestly don’t have any interest in that. That feels like it increases mental overhead, which is the opposite of what I want when working with things like configuration files.

What I needed was a simple and easy way to template my configuration files with minimal setup that fit my existing workflow. Until then, I would just comment/uncomment the correct lines in my config files depending on which device I was using (not fun). I looked at tools like chezmoi, but I found that many would do a little more than I wanted. I think chezmoi is great, but it feels like overkill in my current Linux ecosystem so I don’t want to invest in learning all of its features only to use a few. I’m still keeping it in mind for the future when my setup has matured, however.

Yolk

I was browsing GitHub and when I found yolk. The description sounded interesting, so I read the documentation and decided that it could address my needs.

There are multiple valid ways to configure and use yolk. This is a short guide to get you started rather than a deep-dive into every feature. I’ll be showing the approach that I use, but you don’t have to do it this way. As always, read the docs for more information.

The first thing you need to do is install yolk. I used the cargo install method:

cargo install yolk_dots --locked --profile=dist

This is the point when you would normally run the yolk init command to generate the default file structure. I wanted to reuse the .dotfiles/ structure I had with Stow, so I use --yolk-dir to provide my custom directory as an argument. Right now I just have an alias, but you can also set the YOLK_DIR environment variable according to command help.

alias yolk='yolk --yolk-dir ~/.dotfiles'

It’s now time to get version control working. If you already have Git installed and used yolk init to get started, then there isn’t anything else to do here except remember to interact with the repository correctly (see below). If you made a custom yolk directory, then git init a repository and run yolk safeguard to safeguard the Git folder. This is crucial. The reason is explained on this docs page:

“Yolk wraps the Git CLI to ensure that Git only ever interacts with your dotfiles in their canonical state. If it didn’t do that, you would end up committing the local state of your dotfiles, which would conflict with their state from another machine – which is what yolk is trying to solve.”

Once yolk is set up for version control, remember to use yolk git <command> instead of git <command> to interact with the repository. For example, you commit changes with yolk git commit -m <msg>.

Make an eggs/ folder in the yolk directory to house all your configuration packages. The structure can depend on which deployment strategy you select.

I use a Stow-style merge strategy, which isn’t the default. This means that my ./dotfiles/eggs/<package> directory structures must mimic the structures of their target folders. You might need to do something different if you decide to use the put strategy.

After getting the files where they need to be, you can start inserting templates directly into your configurations. An example that showcases conditionals is included below. Yolk can also perform other operations such as text replacement. Check the template and function reference pages for more information about templating.

/* Customize Waybar font family and size per-device. */

window#waybar {
    color: #959595;
    /*{% if SYSTEM.hostname == "abscissa" %}*/
    font-family: "GohuFont uni14 Nerd Font Propo";
    font-size: 14px;
    /*{% elif SYSTEM.hostname == "moonbeam" %}*/
    /*<yolk> font-family: "GeistMono Nerd Font Propo";*/
    /*<yolk> font-size: small;*/
    /*{% end %}*/
}

Template instructions are written in comments. When yolk evaluates and deploys templated files, it follows the template instructions to determine how to operate on file contents. In the above example, yolk controls which lines to include by commenting disabled blocks out with a special <yolk> prefix. The prefix will be removed when template instructions tell yolk to re-enable/uncomment those lines. You should not add or remove the prefix manually.

Next, make a yolk.rhai file in your yolk directory to tell the program how to deploy your configurations. This is an important file, so I recommend reading the relevant documentation page. A portion of my yolk.rhai with an explanation of what it does is included below. Remember to include the paths of any templated files (relative to egg containing them) in the templates: [] array of the corresponding egg, otherwise template instructions will not be evaluated.

Once you’re finished writing the yolk.rhai file and templating your files, run yolk sync to deploy everything according to what you defined. Remember to yolk sync often when you’re adding and changing configurations, especially if you experience problems with settings not being applied.

Example yolk.rhai file

export let eggs = #{
    bash: #{
        targets: "~",
        strategy: "merge",
        main_file: ".bashrc",
    },
    gammastep: #{
        targets: "~",
        strategy: "merge",
    },
    keyd: #{
        enabled: SYSTEM.hostname == "abscissa",
        targets: "/",
        strategy: "merge",
    },
    waybar: #{
        targets: "~",
        strategy: "merge",
        templates: [".config/waybar/config.jsonc",".config/waybar/style.css"],
        main_file: ".config/waybar/config.jsonc",
    },
}

bash

gammastep

keyd

waybar