close
Skip to content

Bootstrap

mise bootstrap applies the machine setup declared in your mise configuration: packages, files, services, repositories, shell setup, tools, and a final task. Use it for workstation or server setup that needs more than installing [tools]. Run it explicitly when you want to apply that configuration.

Start with the parts your machine needs, preview them, and add more resources as the configuration grows. Each section has its own status and apply commands. For SSH targets, see remote bootstrap.

Example

This small mise.toml configures zsh activation, installs Node.js, and verifies it in a final task. Choose the shell entries for the shell you actually use:

toml
[bootstrap.mise_shell_activate]
zprofile = "shims"
zshrc = "activate"

[tools]
node = "24"

[tasks.bootstrap]
run = "node --version"

Review the configuration before trusting it, then preview and apply it:

sh
mise trust
mise bootstrap --dry-run
mise bootstrap
mise bootstrap status

--yes skips confirmation prompts for an unattended apply. A dry run inspects state and prints proposed actions; hooks and the final task are not executed. Open a new shell after activation files change.

Starting from a repository

Choose the command that matches what your repository contains:

Repository contentsCommandWhere the files go
A bootstrap project with mise.toml and source filesmise bootstrap --from <url>A separate checkout, then targets defined by the project
Global mise configuration such as config.toml, conf.d/, and tasks/mise bootstrap --adopt <url>Your global mise configuration directory
Tracked dotfiles shared through mise bootstrap dotfiles origin setmise bootstrap --adopt <url>Each tracked file's path on this machine

For a walkthrough of sharing tracked dotfiles, see Set up a machine.

A bootstrap project

Use --from to clone a project and apply its mise.toml:

sh
mise bootstrap --from git@github.com:example/dotfiles.git

The checkout defaults to $MISE_DATA_DIR/bootstrap-repo. Use --from-dir to choose another location. mise trusts the repository you supply for this invocation, so review it before running the command.

To select a mise environment, pass -E, for example mise -E work bootstrap --from <url>. The cloned project then loads the matching configuration, such as mise.work.toml.

An existing checkout must have the requested URL as its origin. mise uses the current checkout unless you pass --update to pull newer commits first. That pull only accepts a fast-forward. With --dry-run, mise reports a missing checkout and leaves it uncloned.

Global mise configuration

Use --adopt when the repository contains your global mise configuration:

sh
mise bootstrap --adopt example/mise-config

mise clones it into $MISE_CONFIG_DIR, normally ~/.config/mise, and runs bootstrap using that configuration. Files such as config.toml, config.work.toml, conf.d/, and tasks/ stay available to future mise commands. Pass -E work to select config.work.toml.

If you set $MISE_GLOBAL_CONFIG_FILE, mise clones into that file's parent directory and loads the selected file. An existing non-empty destination must be a Git checkout with the requested URL as its origin. Pass --update to fast-forward it before bootstrap.

Shared dotfile history

A setup repository holds the dotfile history you share through mise bootstrap dotfiles origin set. On another machine, run:

sh
mise bootstrap --adopt you/setup

mise recognizes the repository's .mise-history/format.toml marker and:

  1. Fetches the latest branch into its history store.
  2. Restores the tracked files to their paths on this machine.
  3. Remembers the origin for future synchronization.
  4. Runs bootstrap using the restored mise configuration.

Track the mise configuration and any template sources on the first machine before sharing them. They let bootstrap recreate tools and services and render templates on the next machine. Tracked files can still be restored when the repository contains no global mise configuration.

If an existing file differs, mise asks you to resolve the conflict before restoring files or running the remaining bootstrap steps. Use --dry-run to preview the plan. See history for synchronization and recovery details.

This workflow stores Git history separately from $MISE_CONFIG_DIR; it leaves any existing checkout there as a checkout. If that directory is a Git checkout, its origin must match the requested repository.

Setup repositories always fetch their latest branch. --update controls the subsequent bootstrap's package metadata and declared repository updates.

How it runs

mise bootstrap runs the steps below in order.

Before making changes, mise resolves any required [bootstrap.secrets] used by the files phase. This preflight prevents a missing input from leaving a partially provisioned host.

  1. mise bootstrap accounts apply converges [bootstrap.users] and [bootstrap.groups].
  2. mise bootstrap plugins apply installs package manager plugins declared in [bootstrap.plugins]. Files and directories with phase = "pre-packages" are then applied, before the pre-packages hook.
  3. Built-in managers install missing [bootstrap.packages].
  4. mise bootstrap files apply converges the remaining [bootstrap.files] and [bootstrap.directories] (the default "post-packages" phase).
  5. [bootstrap.services] converges existing Linux systemd system units and user services on Linux, macOS, and Windows. User services with requires_tools = true wait until after tool installation.
  6. mise bootstrap firewall apply converges host firewall policy and rules from [bootstrap.linux.firewall].
  7. mise bootstrap compose apply converges [bootstrap.compose] projects.
  8. mise bootstrap repos apply clones or updates [bootstrap.repos].
  9. mise bootstrap dotfiles apply applies [dotfiles].
  10. mise bootstrap mise-shell-activate apply configures shell activation from [bootstrap.mise_shell_activate].
  11. mise bootstrap macos defaults apply writes [bootstrap.macos.defaults].
  12. mise bootstrap macos launchd-agents apply writes and loads [bootstrap.macos.launchd.agents].
  13. mise bootstrap linux systemd-units apply converges [bootstrap.linux.systemd.units] by writing unit files, enabling/disabling them, and starting/stopping them as configured.
  14. mise bootstrap user apply applies [bootstrap.user].
  15. mise install installs missing [tools].
  16. Plugin package managers apply after their host tools are available, followed by user services with requires_tools = true.
  17. mise run bootstrap runs a task named bootstrap, if one exists.
  18. [bootstrap.hooks.final] runs after the bootstrap task, if configured.

Every mutating run — the full mise bootstrap, each mise bootstrap <part> apply, and the commands that change dotfiles or bootstrap config in place (dotfiles add, unapply, edit, packages use, import, brew tap) — records a pair of history checkpoints: the tracked files before and after the run, plus a journal of what the run changed. Dry runs record nothing.

Use mise bootstrap --skip <part> to skip specific parts. Supported parts are accounts, plugins, packages, files, services, firewall, compose, repos, dotfiles, mise-shell-activate, macos-defaults, macos-launchd-agents, linux-systemd-units, user, tools, task, and final-hook. The old shorter names shell, defaults, launchd, and systemd are still accepted as aliases. The flag can be repeated or comma-separated, for example mise bootstrap --skip tools,task.

Use mise bootstrap --only <part> to run only specific parts. It supports the same part names and can be repeated or comma-separated, for example mise bootstrap --only dotfiles,tools. --only and --skip are mutually exclusive.

Use mise bootstrap --update to refresh system package manager metadata before installing packages (apk: --update-cache, apt: apt-get update, winget: winget source update) and update declared repositories. Check the repo update rules for clean-worktree and fast-forward requirements.

Hook phases can also run before and after the built-in steps: pre-packages, post-packages, pre-repos, post-repos, pre-dotfiles, post-dotfiles, pre-defaults, post-defaults, pre-user, post-user, pre-tools, and post-tools. Hook commands support Tera templates using the declaring config's context, including values such as {{ config_root }}, {{ xdg_config_home }}, and {{ vars.name }}.

The declarative steps compare the requested state with the host and apply needed changes. Hooks and the bootstrap task run on every selected apply, so make them safe to repeat. Bootstrap is a sequence, not a transaction: if a later phase fails, earlier successful changes remain. Fix the reported failure and run bootstrap again.

Previewing changes

Use mise bootstrap --dry-run to preview the selected phases. To narrow an apply while developing a configuration, for example:

sh
mise bootstrap --only dotfiles,tools --dry-run
mise bootstrap --only dotfiles,tools

Select every prerequisite your changes need. --only services does not install the packages or unit files that supply those services.

For a structured resource plan, use mise bootstrap plan. The provisioning planner reports accounts, system packages, privileged files and directories, system services, firewall policy and rules, and Compose projects in dependency order. Other declarative bootstrap parts will join the same graph as they adopt the resource model.

sh
mise bootstrap plan
mise bootstrap plan --json
mise bootstrap plan --detailed-exitcode

With --detailed-exitcode, the command exits 0 when nothing would change, 2 when the plan contains changes, and 1 when planning fails or any resource has an unknown state. Unknown resources do not count as changes, but they block a successful convergence result. A package is unknown when its manager is unavailable on the current platform or cannot install the requested version. This matches apply behavior: unsupported pins remain visible for manual resolution instead of being reported as changes mise would skip.

When mise bootstrap applies or would apply something that needs user follow-up, it prints a final bootstrap: follow-up section after a successful run. Dry runs use bootstrap: follow-up if applied. If a later bootstrap phase fails after earlier phases already produced follow-up items, mise prints those items before returning the error. The section is omitted when there is nothing actionable to report.

By default, bootstrap refuses dotfile conflicts rather than replacing local files. Use mise bootstrap --force-dotfiles when you explicitly want the dotfiles phase to replace conflicting whole-file dotfile targets.

Inspecting state

Use mise bootstrap status to inspect the declarative bootstrap state in one place. It reports every declarative part — secrets, accounts, files and directories, services, firewall, Compose projects, packages, repos, dotfiles, shell activation, macOS defaults, LaunchAgents, systemd units, and login shell — plus [tools] and any system dependencies that installed tools require:

sh
mise bootstrap status
mise bootstrap status --json
mise bootstrap status --missing
mise bootstrap packages status
mise bootstrap repos status
mise bootstrap dotfiles status
mise bootstrap dotfiles apply --dry-run
mise bootstrap dotfiles apply --dry-run --verbose
mise bootstrap mise-shell-activate status
mise bootstrap macos defaults status
mise bootstrap macos launchd-agents status
mise bootstrap linux systemd-units status
mise bootstrap firewall status
mise bootstrap user status

Use mise bootstrap dotfiles history to see the checkpoints bootstrap has recorded — a pair per mutating run, with the tracked files before and after. See History.

sh
mise bootstrap dotfiles history
mise bootstrap dotfiles history show latest
mise bootstrap dotfiles history diff 11 12

mise bootstrap status --missing checks the whole declarative bootstrap surface in one command. The narrower mise bootstrap packages status --missing and mise bootstrap dotfiles status --missing commands are useful when you only want to check one part without installing anything.

What goes where

ConfigUse for
[bootstrap.secrets]Names of secret inputs consumed by managed file templates
[bootstrap.users], [bootstrap.groups]Linux service accounts and groups
[bootstrap.files], [bootstrap.directories]Managed system paths, content, ownership, and permissions
[bootstrap.services]User services on Linux, macOS, and Windows; existing Linux system services
[bootstrap.compose]Docker Compose project lifecycle
[bootstrap.plugins]Package manager plugins
[bootstrap.packages]OS packages from apk, apt, dnf, pacman, brew, flatpak, mas, or winget
[bootstrap.repos]Git repos cloned before dotfiles are applied
[dotfiles]Tracking dotfiles, creating files from sources, and editing blocks or lines
[bootstrap.mise_shell_activate]mise activation snippets in shell startup files
[bootstrap.macos.*]Curated macOS preferences for Dock/Finder/keyboard/trackpad
[bootstrap.macos.defaults]macOS user preferences written through defaults write
[bootstrap.macos.launchd.agents]macOS user LaunchAgents written and loaded with launchctl
[bootstrap.linux.systemd.units]Linux systemd user services managed with systemctl --user
[bootstrap.linux.firewall]Linux host firewall policy and managed rules
[bootstrap.user]Current-user settings such as login_shell
[bootstrap.hooks]Commands that run at named bootstrap phases
[tools]Versioned dev tools managed by mise
[tasks.bootstrap]Anything custom that should run after tools are installed

Use declarative sections when mise can inspect and converge the state. Use [tasks.bootstrap] for imperative setup that does not fit those sections, such as checking authentication or seeding local data. The task runs again on every bootstrap, so guard operations that should happen only once.

Hooks

Hooks run only during explicit mise bootstrap invocations. A hook can be specified as a command string, an array of command strings, or a table with a run field. They use the same default inline shell setting as tasks, stop the bootstrap if they fail, and print the command instead of running it during mise bootstrap --dry-run. Hooks run in the current process environment; use mise exec -- ... inside a hook, or use [tasks.bootstrap], when the command needs tools from [tools] on PATH.

The following hooks assume node, python, and gh are declared in [tools].

toml
[bootstrap.hooks.post-tools]
run = [
  "mise exec -- node --version",
  "mise exec -- python --version",
]

[bootstrap.hooks.final]
run = "mise exec -- gh auth status"

As shorthand, a hook phase can also be set directly:

toml
[bootstrap.hooks]
post-defaults = "killall Dock || true"

Hooks merge across the config hierarchy from global to local, so shared config can define broad machine setup while a project adds its own phase commands. The pre-dotfiles and post-dotfiles phases also wrap mise bootstrap dotfiles apply.

Common workflows

For a walkthrough from your first tracked file to a second machine sharing its changes, see Set up a machine.

New machine

sh
mise trust
mise bootstrap --yes

Add a package

sh
mise bootstrap packages use apk:zlib-dev apt:libssl-dev winget:BurntSushi.ripgrep.MSVC

This writes [bootstrap.packages] and installs what is missing.

Capture an edited dotfile

For a file you already manage in copy mode, save edits back to its source:

sh
$EDITOR ~/.zshrc
mise bootstrap dotfiles add ~/.zshrc

add updates the managed source. For a file mise does not yet manage, it creates a source under dotfiles.root, writes a configuration entry, and applies it. See capturing changes.

For a file you edit in place and want to save in history, use mise bootstrap dotfiles track ~/.zshrc, then set up automatic saves.

Edit a managed dotfile

sh
mise bootstrap dotfiles edit ~/.zshrc
mise bootstrap dotfiles apply ~/.zshrc

For symlinked dotfiles, edit opens the managed source, so it works with the default symlink mode.

Advanced: self-managing config

You can manage the dotfiles repository and the mise global config as dotfiles:

toml
[settings]
dotfiles.root = "~/.dotfiles"

[dotfiles]
"~/.dotfiles" = "~/src/dotfiles"
"~/.config/mise/config.toml" = "~/src/dotfiles/mise/config.toml"

The repo/source must exist before the first apply. Use the real repo path for sources needed during the first run; ~/.dotfiles does not exist until mise creates that symlink. Replacing the active global config affects future mise invocations, so use this pattern carefully.