docs/concepts/projects/init.md
uv supports creating a project with uv init.
When creating projects, uv supports two basic templates: applications and
libraries. By default, uv will create a project for an application. The --lib
flag can be used to create a project for a library instead.
In both cases, uv prefers to define a build system and place source
files in a dedicated src/<project_name>/ directory. Defining a build system allows use of various
Python packaging features, such as adding command-line entry points, and avoids common points of
confusion with the Python import system. Use of a build system can be disabled by using the
--no-package or
--bare options.
!!! note
Prior to v0.12, uv did not define a build system for applications by default.
uv will create a project in the working directory, or, in a target directory by providing a name,
e.g., uv init foo. The working directory can be modified with the --directory option, which will
cause the target directory path to be interpreted relative to the specified working directory. If
there's already a project in the target directory, i.e., if there's a pyproject.toml, uv will exit
with an error.
Application projects are suitable for web servers, scripts, and command-line interfaces.
Applications are the default target for uv init, but can also be specified with the --app flag:
$ uv init example-app
The source code lives in a src directory with a module directory and an __init__.py file:
$ tree example-app
example-app/
├── .python-version
├── README.md
├── pyproject.toml
└── src
└── example_app
└── __init__.py
A build system is defined, so the project will be installed into the environment:
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[project.scripts]
example-app = "example_app:main"
[build-system]
requires = ["uv_build>=0.12.0,<0.13"]
build-backend = "uv_build"
!!! tip
The `--build-backend` option can be used to request an alternative build system.
A command definition is included:
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[project.scripts]
example-app = "example_app:main"
[build-system]
requires = ["uv_build>=0.12.0,<0.13"]
build-backend = "uv_build"
The command can be executed with uv run:
$ cd example-app
$ uv run example-app
Hello from example-app!
A library provides functions and objects for other projects to consume. Libraries are intended to be built and distributed, e.g., by uploading them to PyPI.
Libraries can be created by using the --lib flag:
$ uv init --lib example-lib
!!! note
Libraries always require a packaged project.
A py.typed marker is included to indicate to consumers that types can be read from the library:
$ tree example-lib
example-lib/
├── .python-version
├── README.md
├── pyproject.toml
└── src
└── example_lib
├── py.typed
└── __init__.py
!!! note
A `src` layout is particularly valuable when developing libraries. It ensures that the library
is isolated from any `python` invocations in the project root and that distributed library code
is well separated from the rest of the project source.
A build system is defined, so the project will be installed into the environment:
[project]
name = "example-lib"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[build-system]
requires = ["uv_build>=0.12.0,<0.13"]
build-backend = "uv_build"
!!! tip
You can select a different build backend template by using `--build-backend` with `hatchling`,
`uv_build`, `flit-core`, `pdm-backend`, `setuptools`, `maturin`, or `scikit-build-core`. An
alternative backend is required if you want to create a [library with extension modules](#projects-with-extension-modules).
The created module defines a simple API function:
def hello() -> str:
return "Hello from example-lib!"
And you can import and execute it using uv run:
$ cd example-lib
$ uv run python -c "import example_lib; print(example_lib.hello())"
Hello from example-lib!
Most Python projects are "pure Python", meaning they do not define modules in other languages like C, C++, FORTRAN, or Rust. However, projects with extension modules are often used for performance sensitive code.
Creating a project with an extension module requires choosing an alternative build system. uv supports creating projects with the following build systems that support building extension modules:
maturin for projects with Rustscikit-build-core for projects with C, C++,
FORTRAN, CythonSpecify the build system with the --build-backend flag:
$ uv init --build-backend maturin example-ext
!!! note
Using `--build-backend` implies `--package`.
The project contains a Cargo.toml and a lib.rs file in addition to the typical Python project
files:
$ tree example-ext
example-ext/
├── .python-version
├── Cargo.toml
├── README.md
├── pyproject.toml
└── src
├── lib.rs
└── example_ext
├── __init__.py
└── _core.pyi
!!! note
If using `scikit-build-core`, you'll see CMake configuration and a `main.cpp` file instead.
The Rust library defines a simple function:
use pyo3::prelude::*;
#[pymodule]
mod _core {
use pyo3::prelude::*;
#[pyfunction]
fn hello_from_bin() -> String {
"Hello from example-ext!".to_string()
}
}
And the Python module imports it:
from example_ext._core import hello_from_bin
def main() -> None:
print(hello_from_bin())
The command can be executed with uv run:
$ cd example-ext
$ uv run example-ext
Hello from example-ext!
!!! important
When creating a project with maturin or scikit-build-core, uv configures [`tool.uv.cache-keys`](../../reference/settings.md#cache-keys)
to include common source file types. To force a rebuild, e.g. when changing files outside
`cache-keys` or when not using `cache-keys`, use `--reinstall`.
While defining a build system generally provides a better experience, there are some cases in which it can be easier to omit it and define your Python modules directly in the top-level directory.
Use the --no-package flag to disable using a build system:
$ uv init --no-package example-app
The project includes a pyproject.toml, a sample file (main.py), a readme, and a Python version
pin file (.python-version).
$ tree example-app
example-app/
├── .python-version
├── README.md
├── main.py
└── pyproject.toml
The pyproject.toml includes basic metadata. It does not include a build system, it is not a
package, and will not be installed into the environment:
[project]
name = "example-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
The sample file defines a main function with some standard boilerplate:
def main():
print("Hello from example-app!")
if __name__ == "__main__":
main()
Python files can be executed with uv run:
$ cd example-app
$ uv run main.py
Hello from example-app!
If you only want to create a pyproject.toml, use the --bare option:
$ uv init example-bare --bare
uv will skip creating a Python version pin file, a README, and any source directories or files.
Additionally, uv will not initialize a version control system (i.e., git).
$ tree example-bare
example-bare
└── pyproject.toml
uv will also not add extra metadata to the pyproject.toml, such as the description or authors.
[project]
name = "example-bare"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
The --bare option can be used with other options like --lib or --build-backend — in these
cases uv will still configure a build system but will not create the expected file structure.
When --bare is used, additional features can still be used opt-in:
$ uv init example-bare --bare --description "Hello world" --author-from git --vcs git --python-pin