Bootstrap Packages experimental
mise can ensure machine-global system packages are installed via the [bootstrap.packages] section of mise.toml:
[bootstrap.packages]
"apt:libssl-dev" = "latest"
"apt:build-essential" = "latest"
"brew:postgresql@17" = "latest"
"brew:ffmpeg" = "latest"Each entry is keyed "manager:package" — the manager prefix is required — and the value is a version: "latest" for whatever the manager installs, or a pin in the manager's native format where supported (see the per-manager pages).
mise can also place config files (dotfiles) — see Dotfiles, which uses mise dotfiles commands.
System packages are intentionally separate from [tools]: they are not version-pinned per-project, do not get shims, and are installed machine-globally by the platform's package manager — or, for brew, by mise's built-in Homebrew bottle installer, which doesn't require Homebrew itself. Use them for shared libraries and build dependencies that dev tools need (libssl-dev, postgresql, ffmpeg), not for the dev tools themselves — those belong in [tools].
The [bootstrap] section can also declare macOS defaults ([bootstrap.macos.defaults]), applied by mise bootstrap macos-defaults apply. Current-user login shells ([bootstrap.user].login_shell) are applied by mise bootstrap user apply or mise bootstrap.
Supported package managers
| Manager | Platform | Page |
|---|---|---|
apt | Debian, Ubuntu | apt |
dnf | Fedora, RHEL, CentOS, Rocky, Alma | dnf |
pacman | Arch, Manjaro | pacman |
brew | macOS (arm64), Linux (x86_64/arm64) — no Homebrew required | brew |
Semantics
- Declarative and additive — entries merge across the config hierarchy (global → project) as a union of keys. A project can add packages on top of the global list (and override a global entry's version pin) but not remove them.
- OS-filtered — entries for a manager that isn't available on the current machine are not acted on, so the same config works across platforms:
aptentries are ignored on macOS,dnfentries on Ubuntu, and so on (brewworks on both macOS and Linux).mise bootstrap packages statusandmise doctorstill list unavailable managers so nothing is silently invisible. - Manual installation only — mise never installs system packages implicitly.
mise installwill print a one-time hint when packages are missing, but onlymise bootstrap packages installever installs anything. - Unknown managers are ignored with a warning so configs using managers from newer mise versions still parse.
For current-user login shell setup, use [bootstrap.user].login_shell:
[bootstrap.user]
login_shell = "/bin/zsh"See User Login Shell for details.
Commands
mise bootstrap packages status # table of requested vs installed packages
mise bootstrap packages status --json # machine-readable
mise bootstrap packages status --missing # exit 1 if anything is out of sync (CI check)
mise bootstrap packages install # install whatever is missing (prompts first)
mise bootstrap packages install apt:curl # install specific packages (configured or not)
mise bootstrap packages install --dry-run # print the commands without running them
mise bootstrap packages install --yes # skip the confirmation prompt
mise bootstrap packages install --manager apt
mise bootstrap packages install --update # refresh package manager metadata first
mise bootstrap packages use apt:curl brew:jq # add to [bootstrap.packages] and install
mise bootstrap packages use -g brew:ffmpeg # write to the global config instead
mise bootstrap packages use apt:curl@8.5.0-2 # pin a version (brew pins via the
# formula name: brew:postgresql@17)
mise bootstrap packages upgrade # upgrade installed packages to current versions
mise bootstrap packages upgrade --manager brewmise bootstrap packages use is mise use for system packages: it writes "manager:package" = "version" entries to mise.toml (the local file by default, the global one with -g) and installs whatever is missing. Entries for managers that aren't available on the current machine are written without installing — that's how a shared config picks up apt: lines authored on a Mac.
mise bootstrap packages upgrade refreshes package manager metadata and upgrades the configured packages that are already installed to the newest available version — apt and dnf also honor a version pinned in config (pacman and brew can't install pins, so pinned entries are skipped with a warning). Packages that aren't installed yet are skipped — that's mise bootstrap packages install's job. For brew this pours the formula's current bottle and replaces the old keg.
mise doctor also reports configured system packages and warns when any are missing.
Choosing which managers run
By default mise acts on every configured manager that is available on the current machine. Since availability implies the OS (apt only exists on Debian-family systems, brew wherever a bottle exists), this usually does the right thing without configuration.
If more than one manager could apply — several package managers installed on one machine, or a shared config listing managers you don't want here — pick a subset with the system_packages.managers setting:
[settings]
system_packages.managers = ["apt"]This composes with platform-specific config files (mise.macos.toml, mise.linux.toml) when you want different selections per OS.
sudo
The Linux package managers require root. When not running as root, mise elevates with sudo, which prompts for your password as usual. The same sudo path is used when [bootstrap.user].login_shell needs to add a shell to /etc/shells, and it only happens during an explicit mise bootstrap:
- already root (containers, CI): no sudo, commands run directly
- interactive terminal: e.g.
sudo apt-get install ...with a normal sudo prompt - non-interactive without passwordless sudo: mise errors and prints the exact command to run manually — it never hangs waiting for a password
- the full command line is logged before it runs
Set system_packages.sudo = false to forbid elevation entirely; mise will print the command for you to run yourself instead. The brew manager never needs sudo except once to create /opt/homebrew (see brew).
CI usage
In containers you're typically already root, so no prompts occur:
mise bootstrap packages install --yes
mise installmise bootstrap --yes combines both (and runs a task named bootstrap afterwards, if one is defined) — one command to set up a fresh machine or container.
mise bootstrap packages status --missing exits 1 when packages are missing, which makes a convenient CI check without installing anything.