CLI tool
linux-nvme/nvme-cli avatar
linux-nvme/nvme-cli

linux-nvme/nvme-cli: the reference tool for driving NVMe devices and fabrics from a shell

NVMe management command line interface.

1,888 stars748 forksCGPL-2.0

At a glance

What is it?
nvme-cli is the GPL-2.0 command line tool for managing NVMe devices, built on the libnvme library, and the two together cover local drives, NVMe-oF fabrics over TCP, RDMA and FC, and a set of vendor specific plugins. The repository is where the NVM Express specification is turned into commands, and its documentation includes a chapter by chapter coverage document, a build system based on meson and a Python binding for libnvme.
Who is it for?
Adopt nvme-cli if you administer NVMe storage on Linux, because it is the reference implementation of the specification's command set and a direct way to talk to a fabric endpoint from a shell. Do not adopt it as a fleet management platform, since it is a command line tool with per device commands and plugins rather than a console, and expect to need root or a udev rule for the operations that touch a device.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A CLI on top of libnvme, and why the split exists

nvme-cli is the command line tool for managing NVMe devices, and it is built on the libnvme library. Together they support local NVMe drives, NVMe-oF fabrics over TCP, RDMA and FC, and many vendor specific plugins.

The split into a library and a tool is the design decision that matters. libnvme is the layer that speaks the protocol, encoding admin commands, building fabrics connections, handling the JSON output, and it is the piece that other projects consume, including a Python binding that the repository publishes as `libnvme3` on PyPI. nvme-cli on top of it is the human interface, one subcommand per operation.

That is why the same binary handles both a local drive and a remote fabric endpoint. The transport changes, the commands do not, because the command set is defined by the NVM Express standard rather than by the transport, and that is exactly the property you want from a management tool.

The project lives under the linux-nvme organisation, points at nvmexpress.org for the specification itself, and coordinates on the linux-nvme mailing list at infradead.org, which is where the development discussion happens. The licences differ by component, with nvme-cli under GPL-2.0 and the library under the LGPL, and the `LICENSES/` directory in the tree is where the per file licensing is recorded.

Local drives, fabrics and the plugin system

The scope is broader than a local disk utility, and the three areas are worth separating because they have different failure modes.

Local NVMe drives are the straightforward case, the admin namespace commands that talk to the device directly. NVMe-oF fabrics are the interesting one, since a fabric endpoint is addressed over TCP, RDMA or FC rather than as a local character device, and the fabric path needs a controller on the switch, a host identifier, and a subsystem to log into. The CONFIGURATION.md document in the repository exists for exactly this, covering host identity, NVMe-oF connections and multi-orchestrator coordination, which is the problem of several storage hosts sharing one fabric controller.

Vendor specific plugins are the third leg, and they are why the tool has a plugin directory rather than a fixed command set. Each vendor's device tends to expose a few non standard admin commands, and a plugin turns those into first class subcommands instead of leaving you to send raw hex. The `plugins/` directory is where they live, and the build system lets you select them.

The Makefile shows how that selection is exposed:

code
ifdef PLUGINS
	MESON_ARGS += -Dplugins=$(PLUGINS)
endif

So a distribution or a site can build a trimmed set of plugins, and the option flows through to the meson configuration. That matters for embedded images and for anyone who wants to audit exactly which vendor specific commands are present on a machine.

Building with meson, and the targets that matter

The quick start is three meson commands:

shell
$ meson setup .build
$ meson compile -C .build
# meson install -C .build

and in practice you are unlikely to need them, since the tool is packaged by most Linux distributions, Alpine, Arch, Debian, Fedora, FreeBSD, Gentoo, Ubuntu, NixOS and openSUSE among them. Once installed, the top level documentation is `man nvme`, with `nvme help` for a short summary.

The Makefile is a thin wrapper over meson, and the interesting part is the list of targets beyond the obvious ones. `make test` runs the meson test suite, and `make test-strict` runs only the nvme-cli suite with `--suite nvme-cli`, which is the variant that does not drag the vendored subprojects into the test run. `make dist` produces a source distribution with `meson dist --formats gztar`. `make rpm` sets the udev rules directory and the systemd directory from the rpm macros and builds the spec file, and `nvme.spec.in` and `nvme.control.in` in the tree are the templates for that. `make update-accessors` runs a meson target that regenerates the accessor code, and `make update-subprojects` refreshes the vendored dependencies under `subprojects/`.

There is also a `valgrind.supp` file, which is a suppression file for memory checking runs, and the tree carries `ccan/`, a collection of C utility modules, alongside `etc/`, `scripts/`, `completions/` for shell completion and `tests/`.

One detail in the packaging is a good sign about the release process. `make install` runs meson install with `--skip-subprojects`, so the vendored dependencies are not installed as if they were part of the product.

The specification coverage document is the real reference

Among the documentation links, one is unusual and deserves attention: SPEC-COVERAGE.md, described as libnvme coverage against the NVMe specifications, chapter by chapter.

For a tool whose value is that it implements a standard, a coverage matrix is the honest way to answer the question a user actually has, which is whether the thing I need is supported or whether I will find out halfway through an operation. A chapter by chapter mapping tells you which parts of the specification are implemented, and by implication which are not.

The other documentation entries are the ones you would expect from a mature project, and the fact that they are separated out is itself informative. BUILDING.md covers dependencies, alternative build systems, packaging and plugin selection. CONFIGURATION.md covers host identity, fabric connections and multi-orchestrator coordination. TESTING.md covers pre-built binaries, reproducing CI builds and memory and sanitizer testing. CONTRIBUTING.md covers adding commands and plugins, API naming and the commit and pull request workflow, and SECURITY.md is where security vulnerabilities are reported. NEWS.md is the release history.

The `Documentation/` directory holds the command and plugin man pages, so the per command reference is generated and shipped with the tool rather than living on a website.

There is also a note about AI-assisted development, pointing at a companion repository named nvme-cli-ai, with CONTRIBUTING.md explaining how those resources fit into the workflow. For a project in the storage kernel ecosystem, having a stated position on that is better than silence, and it is the kind of thing a new contributor will ask about.

Python bindings, and the extra daemons in the tree

The `pyproject.toml` at the top of the repository builds the Python binding for the library rather than for the tool. The project is `libnvme3`, described as Python bindings for libnvme3, with the build backend `meson-python` and a build requirement on meson, ninja and swig, so the bindings are generated from the C headers by SWIG rather than hand written.

The licence is LGPL-2.1-or-later, the development status is classified as production stable, and the meson setup arguments are revealing about what is and is not included in the wheel: the nvme tool is disabled, libnvme and the Python bindings are enabled, the PyPI flag is set, and tests, end to end tests and examples are all turned off. The result is a binding package that ships the library and not the command line tool, with no test machinery inside it.

The tree also contains several daemons that are not the CLI, and they show how much more this project is than a disk utility. There is `daemon-util/`, `discoverd/`, `keysd/` and `nvmf-autoconnect/`, which are the pieces that watch for devices, handle discovery and manage keys, and the last of them is the component that automates connecting to a fabric target when it appears. The `keys/` handling in particular is part of the fabric story, since a fabric session involves key exchange with the controller.

None of that is visible from the command name, which is why reading the repository tree is worth the ten minutes it takes.

Where nvme-cli is the wrong tool

The first wrong case is fleet management. nvme-cli is a command line tool with one command per operation, and while it is scriptable and there are plugins, there is no console, no inventory, no role based access and no scheduling. A team that wants a portal for a hundred devices needs a product, not a binary.

The second is a non Linux host. The tool is developed by the Linux NVMe community, its udev rules and systemd integration are Linux specific, and the whole thing is shaped around the Linux NVMe subsystem. On FreeBSD it is packaged, but the target is clearly Linux.

The third is a device whose vendor plugin you do not have. The standard commands are what the specification defines, and the interesting diagnostics on a particular drive frequently live in the vendor extensions. If the plugin is not in `plugins/` or was not built, the command simply is not there.

The fourth is an environment where you cannot get device access. The commands that matter need permission on the device node, and that is root, or a udev rule, or a group membership, and in a container without the right devices mapped you have none of it. The documentation covers packaging and udev rules, and the rpm target wires the udev rules directory into the build, so this is a solved problem in the packaging, but it is a deployment decision you have to make.

On the state of the project, the release history is quick, with v3.0-rc3 on 2026-08-28, v3.0 on 2026-09-07 and v3.1 on 2026-09-18, and the last push to the repository on 2026-10-19. The repository is not archived, the CI runs meson builds, Coverity and clang-analyzer static analysis and codecov coverage, and the licences are separated by component, with GPL-2.0 for the tool and LGPL for the library and the Python bindings.

Editorial conclusion

Adopt nvme-cli if you administer NVMe storage on Linux, because it is the reference implementation of the specification's command set and a direct way to talk to a fabric endpoint from a shell. Do not adopt it as a fleet management platform, since it is a command line tool with per device commands and plugins rather than a console, and expect to need root or a udev rule for the operations that touch a device. Verify first that the plugin you need for your vendor's device is in the `plugins/` directory, that your kernel and libnvme version support the commands you plan to use, and that the specification coverage document matches the release of the NVM Express standard your hardware implements, since v3.0 and v3.1 landed in September 2026.

Frequently asked questions

What is the difference between nvme-cli and libnvme?

nvme-cli is the command line tool for managing NVMe devices, and it is built on the libnvme library. Together they support local NVMe drives, NVMe-oF fabrics over TCP, RDMA and FC, and many vendor specific plugins. The library is also what the Python bindings are generated from, with SWIG, and published as libnvme3.

How do I build nvme-cli from source?

Use meson: `meson setup .build`, `meson compile -C .build` and then `meson install -C .build`, with the install line commented out in the quick start. The Makefile wraps these and adds targets for tests, a strict test run of the nvme-cli suite only, a source distribution, an rpm build and updating the vendored subprojects.

How do I know whether nvme-cli supports the command I need?

The repository includes SPEC-COVERAGE.md, which maps libnvme coverage against the NVMe specifications chapter by chapter, alongside the per command man pages in the Documentation directory. The tool itself also ships `man nvme` and a `nvme help` summary.

Can I select which vendor plugins get built?

Yes. The Makefile passes a PLUGINS variable through to the meson configuration as `-Dplugins=$(PLUGINS)`, so a distribution or a site can build a trimmed set of the vendor specific plugins in the `plugins/` directory.

Is there a Python binding for libnvme?

Yes. The `pyproject.toml` builds `libnvme3`, the Python bindings for libnvme, using meson-python with SWIG generating the binding from the C headers. It requires Python 3.6 or newer, is licensed LGPL-2.1-or-later, and the published package includes the library and the bindings but not the nvme command line tool.

Official sources

  1. License: GPL-2.0
  2. linux-nvme/nvme-cli on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/linux-nvme-nvme-cli.svg)](https://hysenlabs.com/projects/linux-nvme-nvme-cli)

Was this useful?