How to Use uv init to Create a New Python Project
Setting up a traditional Python project takes minutes. Creating one with uv init takes seconds. That’s not an exaggeration - it’s the reality of using Astral’s Rust-based Python package manager.
I’ve been using uv for a while now, and uv init has completely changed how I start new Python projects. No more manually creating pyproject.toml, no more hunting for cookiecutter templates, no more waiting for Poetry to initialize. Just instant project scaffolding with proper structure.
Let me show you exactly how it works.
What is uv init?
uv init is a command that initializes a new Python project with a proper structure. It’s part of uv - the blazingly fast Python package manager from the creators of Ruff.
Here’s why I use it:
- Creates
pyproject.tomlautomatically with sensible defaults - Supports both application and library templates
- Optional: README.md,
.python-versionfile, Git initialization - 10-100x faster than traditional tools like Poetry or pip-tools
There are two modes: default (creates a full project structure) and bare (minimal - only pyproject.toml). I’ll cover both.
Prerequisites
First, install uv if you haven’t already:
# macOS/Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)irm https://astral.sh/uv/install.ps1 | iex
# Or via pippip install uvVerify the installation:
uv --versionYou should see something like uv 0.5.x - the version doesn’t matter much, but make sure it’s recent.
Quick Start - Create Your First Project
Here’s the simplest way to create a new project:
uv init hello-worldcd hello-worldThat’s it. Let me show you what gets created:
hello-world/├── .python-version├── README.md├── main.py└── pyproject.tomlNow run it:
uv run main.pyYou’ll see the output - a simple “Hello from uv!” message. But here’s the thing: uv run doesn’t just execute the script. It creates a virtual environment, installs dependencies, and runs your code. All in one command.
Project Types: Application vs Library
This is important. uv init creates different structures depending on whether you’re building an application or a library.
Application Project (Default)
Use this for web servers, scripts, CLIs - anything that runs rather than gets imported:
uv init my-appStructure:
my-app/├── .python-version├── README.md├── main.py└── pyproject.tomlThe main.py is your entry point. Simple.
Library Project (—lib flag)
Use this when you’re building something meant to be distributed via PyPI:
uv init my-lib --libStructure:
my-lib/├── .python-version├── README.md├── pyproject.toml└── src └── my_lib ├── __init__.py └── py.typedNotice the src/ layout. This is the modern Python convention - it isolates your library code from project root imports, preventing accidental test contamination and making your package work correctly when installed.
The py.typed file? That’s how you tell type checkers (and PyPI) that your library includes type annotations.
Why does this matter? If you ever plan to publish to PyPI or want proper import isolation, use --lib. For scripts and quick experiments, the default app template is fine.
Customizing Project Creation
Sometimes you want less. Sometimes you want more. uv init has flags for both.
Bare Project (Minimal)
For CI/CD automation or when you want complete control:
uv init my-project --bareCreates only pyproject.toml - nothing else:
my-project/└── pyproject.tomlWith Additional Options
Here are the flags I use most:
# With descriptionuv init my-project --description "My awesome project"
# Use author from Git configuv init my-project --author-from git
# Initialize Git repouv init my-project --vcs git
# Pin Python version to .python-versionuv init my-project --python-pinCombine them for maximum efficiency:
uv init example --bare --description "Hello world" --author-from git --vcs git --python-pinUnderstanding pyproject.toml
Here’s what uv init creates:
[project]name = "example"version = "0.1.0"requires-python = ">=3.12"dependencies = []Clean. Minimal. Ready to extend.
The requires-python field comes from your current Python version. If you want a specific version, use --python-pin or manually edit after creation.
Running Your Project with uv run
Now that you have a project, how do you run it?
Basic Execution
uv run main.pyThis handles everything: creates/updates the virtual environment, resolves dependencies, runs your script.
Running with Temporary Dependencies
Need requests just for this one run? No need to add it to your project:
uv run --with requests main.pyThe dependency installs temporarily, runs your script, and leaves your pyproject.toml untouched.
Running with Specific Python Version
uv run --python 3.10 main.pyUseful for testing compatibility or when you need a specific interpreter.
Running Arbitrary Commands
uv run -- flask run -p 3000uv run isn’t limited to Python files. Any command in your project context works.
Adding Dependencies
When you’re ready to actually add dependencies to your project:
# Add a runtime dependencyuv add requests
# Add a dev dependencyuv add --dev pytest
# Add multiple at onceuv add requests httpx beautifulsoup4This modifies your pyproject.toml and creates a lock file. Your dependencies are now reproducible across machines.
Best Practices and Tips
After using uv init extensively, here’s what I’ve learned:
-
Use
--barefor CI/CD - Less noise, more control. Your pipeline knows what it needs. -
Always use
--libfor libraries - The src layout prevents import headaches. Trust me. -
Commit
.python-version- It ensures reproducible builds across machines. -
Use
uv lock- Commit the lock file. It locks your dependency versions. -
Use
uv sync- On other machines, runuv syncinstead ofuv addto install exactly what’s locked.
Conclusion
uv init replaces a handful of tools I used to juggle: Poetry’s project creation, cookiecutter templates, manual pyproject.toml editing. Now it’s one command, sub-second execution.
Key takeaways:
uv initcreates properly structured Python projects in seconds- Default mode = applications,
--lib= libraries with proper src layout - Flags like
--bare,--vcs git, and--python-pincustomize what you get uv runhandles execution with automatic virtual environment management
Try it now:
uv init your-project-namecd your-project-nameuv run main.pyYour turn.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 uv Official Documentation
- 👨💻 uv GitHub Repository
- 👨💻 PEP 517 - pyproject.toml Specification
- 👨💻 uvx vs pipx: Which is Better for Running Python CLI Tools?
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments