Skip to content

Use with mise

mise manages tool versions, environment variables and tasks. Its global configuration is plain files under ~/.config/mise/, so dotsync can sync it like any other dotfile. What syncs is the recipe. Each machine still installs its own tools and keeps its own secrets.

Path Sync it? Why
~/.config/mise/config.toml yes your global tools, settings, [env] and inline tasks
~/.config/mise/conf.d/ yes extra config fragments, if you use them
~/.config/mise/tasks/ yes global file tasks. The executable bit is kept
~/.config/mise/age.txt never the key that decrypts your secrets. dotsync refuses it
~/.config/mise/*.env no plaintext secrets for this machine only (see below)
~/.local/share/mise/ no installed tools: large, platform-specific, and rebuilt by mise install
mise.toml inside a project no it belongs in that project’s own repository

The simplest setup is to manage the whole directory and ignore the files that must stay local:

Terminal window
dotsync add ~/.config/mise -d "mise" --ignore age.txt --ignore '*.env'

dotsync would refuse to upload those two anyway. Ignoring them keeps them out of dotsync status and doctor, which would otherwise list them as held back on every run.

dotsync syncs files. It never runs commands. When config.toml arrives on another machine, the tools it lists aren’t installed until mise installs them. Pick whichever of these suits you:

  • Run it yourself when a tool is missing: mise install. It’s quick when there’s nothing to do.

  • From your shell startup, in the background, so it never slows the prompt down:

    ~/.zshrc
    (mise install --quiet >/dev/null 2>&1 &)
  • As a synced task that you run on each new machine:

    ~/.config/mise/config.toml
    [tasks.bootstrap]
    description = "Install everything this machine needs"
    run = "mise install"

mise use -g rewrites ~/.config/mise/config.toml. If two machines change it before they sync, dotsync reports a conflict: it doesn’t merge, even when the changes are on different lines. Nothing is lost, but you’ll have to pick a version. To make this rarer:

  • Run dotsync sync after mise use -g, so the change reaches the other machines straight away rather than within five minutes.

  • Keep tools for one machine out of the shared file. mise loads every conf.d/*.toml file, so give each machine a local file that isn’t synced:

    Terminal window
    dotsync set ~/.config/mise --ignore local.toml
    mise use --path ~/.config/mise/conf.d/local.toml terraform@1.9 # only on this machine
  • If you do get a conflict, dotsync diff ~/.config/mise/config.toml shows both sides. Edit the local file so it has both changes, then dotsync resolve ~/.config/mise/config.toml --keep local.

Keep one shared config.toml and limit tools to the systems that need them with mise’s os option, rather than keeping one config per OS:

~/.config/mise/config.toml
[tools]
node = "lts"
shellcheck = { version = "latest", os = ["linux"] }

If one machine shouldn’t have your mise config at all, dotsync exclude ~/.config/mise/config.toml on that machine. See per-OS and per-machine differences.

config.toml syncs everywhere, so it must not contain plaintext secrets. dotsync blocks the file if it spots one. mise gives you several ways to avoid storing them there.

A template can call a command when mise loads the environment. The synced file only holds the reference:

~/.config/mise/config.toml
[env]
GITHUB_TOKEN = "{{ exec(command='op read op://dev/github/token') }}"

The secret rules don’t flag this. A value that starts with a brace is read at runtime, not stored.

~/.config/mise/config.toml
[env]
_.file = "~/.config/mise/local.env"

Create ~/.config/mise/local.env on each machine. The --ignore '*.env' above keeps it out of sync. Even without that, dotsync wouldn’t upload it: *.env is on the list of secret paths.

mise can store an age-encrypted value directly in the config (an experimental feature at the time of writing):

Terminal window
mise set --age-encrypt --prompt DB_PASSWORD
~/.config/mise/config.toml
[env]
DB_PASSWORD = { age = { value = "<base64>" } }

Only ciphertext reaches the repository, so the file syncs without any exceptions.

mise can also load a sops-encrypted file such as .env.json or .env.yaml:

~/.config/mise/config.toml
[env]
_.file = { path = "~/.config/mise/.env.json", redact = true }

dotsync recognizes sops files and syncs them even though the name looks like a secret. It still checks their readable lines (keys, comments, _unencrypted values), so no --allow-secrets is needed. Don’t use --allow-secrets on the directory: it would let a plaintext file through too.

Both approaches depend on an age private key, by default ~/.config/mise/age.txt. mise can also use your SSH key. Anyone with that key and a copy of the repository can read every secret, so it has to stay off the repository. dotsync refuses it by path (.config/mise/age.txt, .config/sops/age/*) and by content (AGE-SECRET-KEY-1…).

Copy it to each new machine yourself, once. dotsync never syncs it, and it doesn’t check for it either: until the key is there, the encrypted values simply show up as missing in mise env.

  1. On a machine that has the key: cat ~/.config/mise/age.txt, or store it in your password manager.
  2. On the new machine: paste it into ~/.config/mise/age.txt and chmod 600 ~/.config/mise/age.txt.
  3. Check it works: mise env should now list DB_PASSWORD.

mise can also manage dotfiles itself, with mise dot and a [dotfiles] section in its config. It links, copies or templates files from a source directory, and it can track files where they are, keeping their history in git. With the history watcher and history.sync = "sync", it syncs tracked files between machines too. See mise’s dotfiles docs, and the comparison for how it differs from dotsync.

You can use both, but never let both manage the same file. Each would see the other’s writes as local edits and push them back, and the two histories would keep fighting over the file. In practice:

  • Pick one tool per file. If mise tracks ~/.zshrc, don’t dotsync add it, and the reverse.
  • Watch out for ~/.config/mise/ itself. Syncing it with dotsync also syncs its [dotfiles] entries, including the tracking entries mise writes to conf.d/dotfiles-tracking.toml. Every machine then starts managing those files with mise as well. Either keep dotfile entries out of the synced config (for example with --ignore conf.d/dotfiles-tracking.toml), or let mise manage its own config and don’t add it to dotsync.
  • Moving a file from mise to dotsync: for a tracked file, mise dot untrack <file>; the file stays where it is. For a linked file, first replace the symlink with a real copy of its source, then delete its [dotfiles] entry. Then dotsync add <file>.

Project mise.toml files can define tasks and exec() templates, so mise asks you to mise trust them. Your global config.toml is your own file and doesn’t need that. Once it’s synced, anyone who can push to your dotfiles repository can change what it runs the next time mise loads it. The same is true of your shell startup files, so treat the repository with the same care: keep it private and protect the credentials that can push to it.