Neovim mason-nvim

ID

mason

Home page

https://github.com/mason-org/mason.nvim

Version requirement

>= 2

Platforms

🅱️ BSD · 🐧 Linux · 🍎 macOS · ⨂ Unix · 🪟 Windows

Operations

installed · install · upgrade · remove · sync

purl types

pkg:mason

CLI name

nvim

Every call

nvim --headless <command> -c cquit

Issues and PRs

📦 manager: mason

Source

meta_package_manager/managers/mason.py

Installer of LSP servers, DAP adapters, linters and formatters for Neovim.

Important

mason is not a plugin manager, which is what separates it from Lazy and Vim_Pack. Those install Lua that runs inside the editor; mason installs ordinary developer tools, the same stylua or rust-analyzer binaries another host might get from Homebrew.

Note

Wrapping it is what makes those tools visible at all. mason redirects every backend it shells out to into the package’s own directory: a local npm install rather than a global one, a venv per package, cargo install --root ., GOBIN and GEM_HOME pointed inside. So a pyright installed by mason appears in no other manager’s inventory, and without this wrapper mpm would not see it.

Caution

Reads and writes drive Neovim differently, and deliberately.

The inventory is read by a --clean process straight off mason’s own install tree, costing no plugin loading and immune to whatever the user’s configuration does. Mutations cannot work that way: MasonInstall and its siblings are user commands that exist only once mason is loaded, so those run without --clean and let the configuration supply them. That is mason’s own documented recipe for unattended use.

Note

Every mutating command blocks in headless mode rather than returning while work continues in the background: mason branches on #vim.api.nvim_list_uis() == 0 and runs the transaction synchronously, refusing an unknown package name up front instead of failing silently.

Warning

The install root is assumed to be mason’s default. A configuration moving install_root_dir elsewhere leaves the inventory empty, since finding the override would mean loading the very plugin the read path avoids.

Documentation: mason.nvim.

What mpm adds to mason

mpm reaches across every manager at once, not mason alone: mpm installed and mpm outdated cover mason alongside every other manager you run in one table, mpm upgrade --all updates them together, and mpm sbom exports the whole machine as one bill of materials.

Every mpm command also gains --dry-run and --plan previews, cross-scheme version comparison and purl identifiers. See manager augmentations for how each one is built.

Your mason commands, in mpm

You already know mason: each operation maps one-to-one onto mpm, in an interface shared by every manager.

To…

With mason

With mpm

List what’s installed

nvim --clean 'lua local root = vim.fn.stdpath("data") .. "/mason" .. "/packages" for _, dir in ipairs(vim.fn.glob(root .. "/*", true, true)) do local f = dir .. "/mason-receipt.json" if (vim.uv or vim.loop).fs_stat(f) then local ok, r = pcall(vim.json.decode, table.concat(vim.fn.readfile(f), "\n")) if ok and r and r.name then local s = r.source or r.primary_source io.write(r.name .. "\t" .. ((s and s.id) or "") .. "\n") end end end os.exit(0)' 'cquit'

mpm --mason installed

Install a package

nvim 'MasonInstall stylua' 'qall' 'cquit'

mpm install pkg:mason/cquit

Upgrade one package

nvim 'MasonInstall stylua' 'qall' 'cquit'

mpm --mason upgrade cquit

Remove a package

nvim 'MasonUninstall stylua' 'qall' 'cquit'

mpm remove pkg:mason/cquit

Prefix any command above with --dry-run to simulate the underlying manager calls without touching the system: the safe way to watch what mpm would do before trusting it.

Operations

Operation

Supported

installed

outdated

orphans

search

install

upgrade

upgrade_all

remove

sync

cleanup

doctor

Selecting and configuring mason

Deselect mason for a single run with --no-mason, or persist the choice in your configuration:

[mpm]
mason = false

The arguments and environment variables listed in the box atop this page are forced on every mason call, so runs stay quiet, non-interactive and reproducible: the defaults you would set in CI anyway.

Keep it enabled but tune how mpm drives it with a per-manager override:

[mpm.managers.mason]
timeout = 900

mpm config-template mason prints every overridable attribute as a ready-to-paste block.

Recipes

A few jobs you would otherwise script around mason, one mpm command each:

  • Snapshot and clone a machine: mpm --mason dump mason.toml, then mpm restore mason.toml on the next one.

  • Export a compliance SBOM: mpm --mason sbom (CycloneDX by default, --spdx for SPDX).

Privilege escalation

mpm runs this manager as the current user and never prepends sudo by default. Flip the policy for its privileged operations with --sudo or the per-manager sudo override.

See privilege escalation for the full policy.

Cooldown

State of Neovim mason-nvim’s release-age gating, from the cooldown support table:

Status: ❌ None

A cooldown only pays off where a compromised release can be withdrawn while the clock runs, and can only be emulated where the registry dates its releases. From the retraction table:

  • Registry: GitHub release assets

  • Retraction: None: withdrawing a build is the upstream author deleting their own release or tag. Nothing sits between them and the user

  • Publish date: ✅ server-set published_at on each release (REST API)

With --cooldown set, mpm skips this manager’s install and upgrade operations rather than run them unguarded (fail-closed); --allow-unsupported-managers opts back in.

Version probe

The version is probed by running:

$ nvim --clean --headless -c lua local d = vim.fn.stdpath("data") local c = vim.fn.glob(d .. "/lazy/mason.nvim", true, true) vim.list_extend(c, vim.fn.glob(d .. "/site/pack/*/*/mason.nvim", true, true)) for _, p in ipairs(c) do vim.opt.rtp:prepend(p) local ok, m = pcall(require, "mason.version") if ok then io.write("mason " .. m.VERSION) break end end os.exit(0)
mason v2.3.1

and extracted with:

r"mason v?(?P<version>\S+)"

Reference traces

Raw native outputs captured in the manager source: the reference mpm’s parsers were written against. If you know Neovim mason-nvim well and a transcript below looks wrong, or a newer release changed its output format, report it.

$ nvim --headless --clean \
> -c 'lua local root = vim.fn.stdpath("data") .. "/mason" .. "/packages" for _, dir in ipairs(vim.fn.glob(root .. "/*", true, true)) do local f = dir .. "/mason-receipt.json" if (vim.uv or vim.loop).fs_stat(f) then local ok, r = pcall(vim.json.decode, table.concat(vim.fn.readfile(f), "\n")) if ok and r and r.name then local s = r.source or r.primary_source io.write(r.name .. "\t" .. ((s and s.id) or "") .. "\n") end end end os.exit(0)' \
> -c 'cquit'
stylua	pkg:github/johnnymorganz/stylua@v2.5.2

Feed any of these through mpm and the raw output becomes one uniform table, the same shape for every manager: filter it, project columns, or export it (mpm --mason installed --output json, or csv, toml, yaml), each package carrying a purl and a version comparable across managers.

Changelog

  • 7.7.0.dev0 (unreleased)

    • Implement mason, the Neovim installer for LSP servers, DAP adapters, linters and formatters. The inventory is read straight off mason’s install tree by a --clean Neovim, so it costs no plugin loading and reports packages that reach no other manager: mason redirects every backend it uses into the package’s own directory, so a tool it installed is invisible to npm, pip and the rest.