Skip to main content

Setuptools plugin for Rust extensions

github actions pypi package readthedocs Ruff

setuptools-rust is a plugin for setuptools to build Rust Python extensions implemented with PyO3 or rust-cpython.

Compile and distribute Python extensions written in Rust as easily as if they were written in C.

Quickstart

The following is a very basic tutorial that shows how to use setuptools-rust in pyproject.toml. It assumes that you already have a bunch of Python and Rust files that you want to distribute. You can see examples for these files in the examples/hello-world directory in the github repository. The PyO3 docs have detailed information on how to write Python modules in Rust.

hello-world
├── python
│   └── hello_world
│       └── __init__.py
└── rust
    └── lib.rs

Once the implementation files are in place, we need to add a pyproject.toml file that tells anyone that wants to use your project how to build it. In this file, we use an array of tables (TOML jargon equivalent to Python's list of dicts) for [[tool.setuptools-rust.ext-modules]], to specify different extension modules written in Rust:

# pyproject.toml
[build-system]
requires = ["setuptools", "setuptools-rust"]
build-backend = "setuptools.build_meta"

[project]
name = "hello-world"
version = "1.0"

[tool.setuptools.packages]
# Pure Python packages/modules
find = { where = ["python"] }

[[tool.setuptools-rust.ext-modules]]
# Private Rust extension module to be nested into the Python package
target = "hello_world._lib"  # The last part of the name (e.g. "_lib") has to match lib.name in Cargo.toml,
                             # but you can add a prefix to nest it inside of a Python package.
path = "Cargo.toml"      # Default value, can be omitted
binding = "PyO3"         # Default value, can be omitted

Each extension module should map directly into the corresponding [lib] table on the Cargo manifest file:

# Cargo.toml
[package]
name = "hello-world"
version = "0.1.0"
edition = "2021"

[dependencies]
pyo3 = "0.25"

[lib]
name = "_lib"  # private module to be nested into Python package,
               # needs to match the name of the function with the `[#pymodule]` attribute
path = "rust/lib.rs"
crate-type = ["cdylib"]  # required for shared library for Python to import from.

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# See also PyO3 docs on writing Cargo.toml files at https://pyo3.rs

You will also need to tell Setuptools that the Rust files are required to build your project from the source distribution. That can be done either via MANIFEST.in (see example below) or via a plugin like setuptools-scm.

# MANIFEST.in
include Cargo.toml
recursive-include rust *.rs

With these files in place, you can install the project in a virtual environment for testing and making sure everything is working correctly:

# cd hello-world
python3 -m venv .venv
source .venv/bin/activate  # on Linux or macOS
.venv\Scripts\activate     # on Windows
python -m pip install -e .
python
>>> import hello_world
# ... try running something from your new extension module ...
# ... better write some tests with pytest ...

Environment variables for configuration

As well as all environment variables supported by Cargo, setuptools-rust also supports the following:

  • SETUPTOOLS_RUST_CARGO_PROFILE: used to override the profile of the Rust build. Defaults to release, e.g. set to dev to do a debug build.

Next steps and final remarks

  • When you are ready to distribute your project, have a look on the notes in the documentation about building wheels.

  • Cross-compiling is also supported, using one of crossenv, cross or cargo-zigbuild. For examples see the test-crossenv and test-cross and test-zigbuild Github actions jobs in ci.yml.

  • You can also use [[tool.setuptools-rust.bins]] (instead of [[tool.setuptools-rust.ext-modules]]), if you want to distribute a binary executable written in Rust (instead of a library that can be imported by the Python runtime). Note however that distributing both library and executable (or multiple executables), may significantly increase the size of the wheel file distributed by the package index and therefore increase build, download and installation times. Another approach is to use a Python entry-point that calls the Rust implementation (exposed via PyO3 bindings). See the hello-world example for more insights.

  • For a complete reference of the configuration options, see the API reference. You can use any parameter defined by the RustExtension class with [[tool.setuptools-rust.ext-modules]] and any parameter defined by the RustBin class with [[tool.setuptools-rust.bins]]; just remember to replace underscore characters _ with dashes - in your pyproject.toml file.

  • Cargo.toml allow only one [lib] table per file. If you require multiple extension modules you will need to write multiple Cargo.toml files. Alternatively you can create a single private Rust top-level module that exposes multiple submodules (using PyO3's submodules), which may also reduce the size of the build artifacts. You can always keep your extension modules private and wrap them in pure Python to have fine control over the public API.

  • If want to include both [[tool.setuptools-rust.bins]] and [[tool.setuptools-rust.ext-modules]] in the same macOS wheel, you might have to manually add an extra build.rs file, see PyO3/setuptools-rust#351 for more information about the workaround.

  • For more examples, see:

    • hello-world: a more complete version of the code used in this tutorial that mixes both [[tool.setuptools-rust.ext-modules]] and [[tool.setuptools-rust.bins]] in a single distribution.
    • html-py-ever: a more advanced example that uses Rust crates as dependencies.
    • rust_with_cffi: uses both Rust and CFFI.
    • namespace_package: integrates Rust-written modules into PEP 420 namespace packages.
    • hello-world-script: uses Rust only for creating binary executables, not library modules.

Release files for setuptools-rust 1.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for setuptools-rust 1.13.0
File Size Uploaded
setuptools_rust-1.13.0.tar.gz 314.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for setuptools-rust 1.13.0
File Interpreter ABI Platform
setuptools_rust-1.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 344.6 kB

Release files / setuptools_rust-1.13.0.tar.gz

Download URL setuptools_rust-1.13.0.tar.gz
Size 314.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f2afcf4baeee689910ce49cfa8aad4e08cce72f417449bcc32891b8664fdc726
BLAKE2b-256 checksum
How to use checksums
68bab31781d61bf9ee3c232a1d1160db11c11cdeae1d44e06c90723b25a8279f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 27, 2026.

Transparency log

Release files / setuptools_rust-1.13.0-py3-none-any.whl

Download URL setuptools_rust-1.13.0-py3-none-any.whl
Size 30.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
666439c4d90e968bb625bcf87ec0aa02b4f49e599d2f5dc255c633a04e8eca99
BLAKE2b-256 checksum
How to use checksums
0b80909e46e684e47b116ed145bf2a1a8f5f7c9d90e8c3f8f7fce6a529c0068d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.13.0 This release

2 release files

1.12.1

2 release files

1.12.0

2 release files

1.11.0

2 release files

1.9.0

2 release files

1.8.1

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.12.1

2 release files

0.11.6

2 release files

0.11.5

2 release files

0.11.3

2 release files

0.11.2

2 release files

0.10.6

1 release file

0.10.5

1 release file

0.10.4

1 release file

0.9.2

2 release files

0.9.1

1 release file

0.9.0

1 release file

0.8.4

1 release file

0.8.3

1 release file

0.8.2

1 release file

0.8.1

1 release file

0.8.0

1 release file

0.7.2

1 release file

0.7.1

1 release file

0.7.0

1 release file

0.6.4

1 release file

0.6.3

1 release file

0.6.2

1 release file

0.6.1

1 release file

0.6.0

1 release file

0.5.1

1 release file

0.5.0

1 release file

0.4.2

1 release file

0.4.1

1 release file

0.4

1 release file

0.3.1

1 release file

0.3

1 release file

0.2

1 release file

0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page