Skip to content

Use uv to manage a GenAI project

Beginner-friendly · 12 min · Windows & macOS

uv is a fast tool from Astral that replaces pip, venv and pip-tools with one command. It creates the virtual environment for you, installs packages in seconds, and records exact versions so your GenAI project works the same on every machine.

Why use uv?

Task With pip With uv
Create a virtual environment python -m venv .venv + activate it Automatic — no activation needed
Install a package pip install openai uv add openai (also records it in pyproject.toml)
Lock exact versions pip freeze > requirements.txt (by hand) uv.lock is updated automatically
Run your code Activate the environment first, then python main.py uv run main.py
Get a specific Python version Download an installer uv python install 3.12
Speed Normal Usually many times faster

Why it matters for GenAI

LLM libraries (openai, langchain, llama-index…) release new versions constantly. A lock file stops a teammate — or your server — silently getting a newer version that breaks your code.


Step 1 — Install uv

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Or with winget: winget install --id=astral-sh.uv -e

curl -LsSf https://astral.sh/uv/install.sh | sh

Or with Homebrew: brew install uv

Close and reopen your terminal, then check:

uv --version

You should see something like uv 0.x.y. (Already have Python? pip install uv works too.)


Step 2 — Create a project

uv init --no-package rag-assistant
cd rag-assistant

uv creates these files:

rag-assistant/
├── .gitignore         ← already ignores .venv and other junk
├── .python-version    ← which Python version the project uses
├── README.md
├── main.py            ← a "Hello" starter script
└── pyproject.toml     ← project name + list of dependencies

Why --no-package?

Recent uv versions make plain uv init create a packaged layout (a src/ folder and a command-line entry point) — great for libraries, but more than a simple GenAI app needs. --no-package gives you the simple main.py layout shown above.

Run the starter script to check everything works:

uv run main.py
Hello from rag-assistant!

The first uv run quietly creates the .venv folder and a uv.lock file — you never have to create or activate the environment yourself.


Step 3 — Add GenAI packages

uv add openai python-dotenv

This does three things at once:

  1. Installs the packages into .venv.
  2. Adds them to pyproject.toml:

    pyproject.toml
    [project]
    name = "rag-assistant"
    version = "0.1.0"
    requires-python = ">=3.11"
    dependencies = [
        "openai>=…",
        "python-dotenv>=…",
    ]
    
  3. Writes every exact version (including dependencies of dependencies) to uv.lock.

Tools only you need while developing (tests, formatters) go in a separate dev group, so they're not installed on your server:

uv add --dev pytest ruff

Need a version range? Quote it: uv add "openai>=1.40". Remove a package with uv remove python-dotenv.


Step 4 — Write and run some GenAI code

Create a .env file for your key. uv's .gitignore already ignores .venv, but not .env — add a line .env to .gitignore yourself so the key never reaches GitHub:

.env
OPENAI_API_KEY=sk-your-key-here

Replace main.py with:

main.py
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()  # read OPENAI_API_KEY from the .env file
client = OpenAI()  # the key is picked up automatically


def main():
    reply = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Explain RAG in one sentence."}],
    )
    print(reply.choices[0].message.content)


if __name__ == "__main__":
    main()

Run it — no activation step:

uv run main.py

Other things you can run the same way:

uv run python                 # an interactive Python shell inside the project
uv run pytest                 # your tests (dev dependency)
uv run ruff check .           # lint your code (dev dependency)

Prefer activating?

You still can: .venv\Scripts\activate (Windows) or source .venv/bin/activate (macOS/Linux), then use python main.py as usual. VS Code also detects .venv automatically.


Step 5 — Choose the Python version

uv python install 3.12        # download Python 3.12 (no installer needed)
uv python pin 3.12            # make this project use it (updates .python-version)

uv uses the pinned version for uv run and uv sync from then on.


Step 6 — Share the project with your team

Commit these files: pyproject.toml, uv.lock, .python-version — and never .venv/ or .env.

A teammate (or your CI server) clones the repo and runs:

uv sync

That creates .venv with exactly the versions in uv.lock. In CI, use uv sync --locked — it fails if uv.lock is out of date with pyproject.toml, instead of quietly installing something else. (--frozen skips that check entirely, so prefer --locked in CI.)

You want to… Command
See what's installed and why uv tree
Upgrade one package uv lock --upgrade-package openai then uv sync
Upgrade everything uv lock --upgrade then uv sync
Install without dev tools (servers) uv sync --no-dev

Step 7 — Run tools without installing them (uvx)

uvx runs a command-line tool in a temporary, isolated environment — handy for one-off jobs:

uvx ruff check .              # lint
uvx ruff format .             # format
uvx --from mkdocs-material mkdocs serve    # preview a docs site

Step 8 — Moving an existing pip project to uv

uv init --no-package .            # inside your existing project folder
uv add -r requirements.txt        # import every package into pyproject.toml + uv.lock

Some platforms still expect a requirements.txt. Generate it from the lock file:

uv export --format requirements-txt --no-hashes --no-dev > requirements.txt

Step 9 — uv in Docker

Dockerfile
FROM python:3.12-slim

# Copy the uv binaries from the official image
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# Install dependencies first (cached until pyproject.toml or uv.lock change)
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev

# Then copy your code
COPY . .

CMD ["uv", "run", "main.py"]

pip → uv cheat sheet

pip / venv uv
python -m venv .venv (automatic)
pip install openai uv add openai
pip install -r requirements.txt uv add -r requirements.txt (or uv pip install -r requirements.txt)
pip uninstall openai uv remove openai
pip freeze > requirements.txt uv lock (automatic) · uv export for a requirements file
python main.py uv run main.py
pip list uv tree

Troubleshooting

You see… Fix
'uv' is not recognized… / command not found: uv Close and reopen the terminal after installing; if it persists, re-run the installer
running scripts is disabled (Windows installer) Use the exact command in step 1 — it includes -ExecutionPolicy ByPass
uv run main.py → program not found The project was created with the packaged layout (no main.py). Run uv run <project-name>, or create the project with uv init --no-package
ModuleNotFoundError when running python main.py You ran plain python, outside the project environment — use uv run main.py (or activate .venv)
The lockfile at uv.lock needs to be updated, but --locked was provided Someone changed pyproject.toml without re-locking — run uv lock and commit uv.lock
warning: VIRTUAL_ENV=… does not match the project environment path .venv Another project's environment is still active — run deactivate (uv uses the project's own .venv anyway)

Next: use your new project to build a RAG chatbot — swap the pip install step for uv add openai.