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¶
Close and reopen your terminal, then check:
You should see something like uv 0.x.y. (Already have Python? pip install uv works too.)
Step 2 — Create a project¶
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:
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¶
This does three things at once:
- Installs the packages into
.venv. -
Adds them to
pyproject.toml: -
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:
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:
Replace main.py with:
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:
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:
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¶
Step 9 — uv in Docker¶
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.