Command-Line Interface

A simple, correct Python build frontend.

By default, a source distribution (sdist) is built from the project root and a binary distribution (wheel) is built from the sdist. If this is undesirable, you can pass --sdist and/or --wheel to build distributions independently of each other.

The positional srcdir argument also accepts a .tar.gz source distribution. Build checks the filename and the presence of PKG-INFO, extracts the archive into a temporary directory, and runs the wheel build against the extracted source. The default --outdir is the directory containing the archive. --sdist errors against an archive, since the archive already is an sdist.

python -m build

    A simple, correct Python build frontend.

    By default, a source distribution (sdist) is built from the project root
    and a binary distribution (wheel) is built from the sdist.
    If this is undesirable, you can pass `--sdist` and/or `--wheel`
    to build distributions independently of each other.
python -m build [-h] [--version] [--quiet | --verbose] [--outdir PATH]
                [--sdist-extract-dir PATH] [--sdist] [--wheel] [--metadata]
                [--report PATH] [--config-setting KEY=[VALUE] | --config-json JSON_STRING]
                [--installer {pip,uv} | --no-isolation] [--env-dir PATH]
                [--dependency-constraints-txt PATH] [--skip-dependency-check]
                [srcdir]

python -m build positional arguments

  • srcdir - source directory, .tar.gz source distribution, or (with –metadata) a .whl to read metadata from (defaults to the current working directory)

python -m build global options

  • -h, --help - show this help message and exit

  • --version, -V - show program’s version number and exit

  • --quiet, -q - reduce verbosity (default: 0)

  • --verbose, -v - increase verbosity (default: 0)

python -m build build options

  • --outdir PATH, -o PATH - output directory (defaults to {srcdir}/dist). Cannot be used together with --metadata

  • --sdist-extract-dir PATH - extract the intermediate sdist to PATH (created if missing and kept afterwards) instead of a random temporary directory; reusing it across rebuilds gives compiler caches such as ccache/sccache a stable source path. Only affects the default (via-sdist) build and building a wheel from an sdist

  • --sdist, -s - build a source distribution (disables the default behavior)

  • --wheel, -w - build a wheel (disables the default behavior)

  • --metadata - print out a wheel’s metadata in JSON format, building it first unless the source argument is already a .whl. Cannot be used in conjunction with --sdist or --wheel

  • --report PATH - write a machine-readable JSON report of the built artifacts (name, path, kind, size and SHA-256 hash) to this path. Cannot be used together with --metadata

  • --config-setting KEY=[VALUE], -C KEY=[VALUE] - settings to pass to the backend. Multiple settings can be provided. Settings beginning with a hyphen will erroneously be interpreted as options to build if separated by a space; use --config-setting=--my-setting -C--my-other-setting instead. A setting passed without =VALUE is given an empty value, but this form is not supported by pip; write KEY= instead for compatibility

  • --config-json JSON_STRING - settings to pass to the backend as a JSON object. This is an alternative to --config-setting that allows complex nested structures. Cannot be used together with --config-setting

python -m build installation options

  • --installer INSTALLER - Python package installer to use (defaults to pip)

  • --no-isolation, -n - disable building the project in an isolated virtual environment. Build dependencies must be installed separately when this option is used

  • --env-dir PATH - create the isolated build environment at this location instead of a temporary directory. The location must be empty; it is removed on success and kept on failure so it can be inspected

  • --dependency-constraints-txt PATH - constrain build dependencies using a constraints.txt when installing dependencies

  • --skip-dependency-check, -x - do not check that build dependencies are installed

Isolation Behavior

By default build will build the package in an isolated environment, but this behavior can be disabled with --no-isolation. When using isolation, build creates a temporary virtual environment, installs the build dependencies specified in your pyproject.toml, runs the build, and then cleans up the environment. This ensures reproducible builds regardless of what packages are installed in your development environment.

Pass --env-dir PATH to put the environment at a fixed location instead of a temporary directory. The location must be empty. build removes it after a successful build and keeps it after a failure so you can inspect it. A fixed path helps compilation caches like ccache and sccache, which treat a changed build-environment path as a new file and miss the cache. You cannot combine --env-dir with --no-isolation.

When a build fails, --env-dir and --sdist-extract-dir keep the environment and the extracted sources for inspection; see Debug a failed build.

Dependency Check

With --no-isolation, build does not install anything; it checks that the build dependencies are already present in the interpreter running build. When a requirement is unmet it exits with an Unmet dependencies error that names the interpreter checked and, for each requirement, the version specifier that was wanted and the version that was found (not installed when absent):

ERROR Unmet dependencies (checked against /usr/local/bin/python3.9):
    anndata>=0.7.4
        wanted: >=0.7.4
        found: not installed
    matplotlib>=3.4 -> kiwisolver>=1.0.1
        wanted: >=1.0.1
        found: 1.0.0

Transitive requirements are shown as a parent -> child chain; the wanted/found lines describe the unmet leaf. Pass --skip-dependency-check to skip this check (see Basic Usage).

Verbose Output

Repeating -v raises the verbosity level. Each level adds to the previous one:

  • -v streams the output of the environment-creation and dependency-installation subprocesses.

  • -vv additionally passes -v through to the installer.

Regardless of verbosity, after installing the build dependencies of an isolated build, build prints a summary of the resolved versions, one name==version per line. build reads these from the isolated environment’s installed metadata, so they reflect what was installed rather than the specifiers in pyproject.toml:

$ python -m build --wheel
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools >= 42.0.0
* Getting build dependencies for wheel...
* Installed build dependency versions:
  - setuptools==82.0.1
* Building wheel...
Successfully built mypackage-1.0.0-py3-none-any.whl

build reports this for isolated builds only; with --no-isolation build installs nothing, so inspect the active interpreter with your installer instead (for example pip list).

Build Report

--report PATH writes a JSON description of the built artifacts to PATH after a successful build. The artifact names are dynamic (they encode version, Python, ABI and platform tags), so this gives scripts and CI a stable way to refer to the produced files instead of globbing dist/. Build writes the report to a file it controls, not to standard output, because the build backend may write to stdout/stderr too.

$ python -m build --report build-report.json
$ twine upload $(jq -r '.artifacts[].path' build-report.json)

Note

Keep the report out of the output directory: tools commonly upload dist/* wholesale (twine upload dist/*), and a stray non-distribution file there can break that. The write is atomic, so a reader never sees a partial file; builds running in parallel still need a distinct PATH each to avoid overwriting one another’s report.

The schema is:

{
  "version": "1.0",
  "artifacts": [
    {
      "name": "mypackage-1.0.0.tar.gz",
      "path": "dist/mypackage-1.0.0.tar.gz",
      "kind": "sdist",
      "size": 852,
      "hashes": {
        "sha256": "dbd5486e6e893663263caf84a4b87d67cc28f6963b6650f69eaa54b78e42ece4"
      }
    },
    {
      "name": "mypackage-1.0.0-py3-none-any.whl",
      "path": "dist/mypackage-1.0.0-py3-none-any.whl",
      "kind": "wheel",
      "size": 1121,
      "hashes": {
        "sha256": "ef460897fdce998634efc3385aa4261b4280a2fe2ab0e08ddcacc8496658465d"
      }
    }
  ]
}

version is the schema version. Each artifact lists its name (basename), path (relative to the current directory, mirroring --outdir), kind (sdist or wheel), size in bytes, and hashes keyed by algorithm. --report cannot be combined with --metadata.

To inspect a wheel listed in the report, pass its path straight to --metadata: when the source argument is a .whl file, build reads METADATA from the archive and prints it as JSON instead of building anything.

$ python -m build --report build-report.json
$ python -m build --metadata "$(jq -r '.artifacts[] | select(.kind=="wheel") | .path' build-report.json)"

Alternative CLI Script

A pyproject-build CLI script is also available, which is functionally identical to python -m build. This is useful for tools like pipx that prefer direct script entry points.

$ pyproject-build
$ pyproject-build --help

Both commands accept the same options and behave identically.

Common Patterns

For practical usage examples and workflows, see Basic Usage.

See Also