Skip to main content

Start Your First Python Project with uv init

UV Series · Project Setup

Start Your First Python Project with uv init

The moment uv starts to make sense is when you stop thinking about it as a command catalog and use it to create a real project. In this post, we will start with an empty terminal, create a project with uv init, inspect the files uv creates, and run the starter code in the managed environment.

UV Series

Goal

Create a real uv project and understand every file that appears.

Main idea

A uv project is centered on pyproject.toml, a managed environment, and a lockfile.

Outcome

You will know what uv init makes and how to run the project without guessing.

The shift to make A uv project is not just a folder with Python files in it. It is a folder with declared dependencies, a Python version hint, and a predictable environment that uv can recreate.
Create the project

Run uv init and Step Into the Folder

Start with a new directory name:

uv init my-first-uv-project
cd my-first-uv-project

By default, uv creates an application project. That is the right choice for most beginners, because it gives you a simple executable main.py and avoids package structure decisions on day one.

Right after uv init, your folder should look roughly like this:

my-first-uv-project/
├── .gitignore
├── .python-version
├── README.md
├── main.py
└── pyproject.toml

This is enough to begin writing Python immediately.

Your first run

Run the Starter Program with uv run

Now run the file uv created:

uv run main.py

That single command does more than beginners usually realize. It checks whether the project is in sync, creates the environment if needed, and then runs the command inside the correct project environment.

That is why uv run is so central. It removes the usual “wait, which Python am I using?” problem.

Project structure

What Each File Is For

pyproject.toml

This is the heart of the project. It stores the project name, version, Python requirement, and dependencies. When you later run uv add, this file changes.

.python-version

This is the version hint that tells uv which Python version the project expects. That is one reason uv can create the right environment without you micromanaging it.

main.py

This is just the starter application file. Think of it as a placeholder that proves the workflow works.

README.md

This is where you can document what the project is and how to run it. It matters more than beginners think once a project outlives its first day.

.gitignore

This keeps generated files like local environments and caches out of version control.

What appears later

Why .venv and uv.lock Show Up After You Start Working

Two important project parts often appear after you run a project command like uv run or uv sync:

.venv/
uv.lock

.venv is the local virtual environment for the project. Your packages live there. Editors also use it to understand imports and completions.

uv.lock records the resolved package versions. That is what makes the project reproducible instead of “whatever happened to install on this machine.”

Good beginner rule Commit uv.lock to version control. It helps every machine resolve the same environment instead of drifting over time.
Application or package?

When Default uv init Is Enough and When --package Makes Sense

For scripts, small tools, and early learning, the default application template is enough. It gives you a main.py and keeps the file structure obvious.

Use uv init --package your-name when you are building something that should behave like an installable Python package, especially if you want a src/ layout or plan to publish it later.

For this series, the application template is perfect. We are learning the project workflow first, not packaging strategy.

A tiny edit

Change the Starter File So the Workflow Feels Real

Open main.py and make a harmless change:

def main():
    print("Hello from my-first-uv-project!")

if __name__ == "__main__":
    main()

Now run it again:

uv run main.py

That feedback loop is the core beginner rhythm in uv: edit a file, run with uv run, then add dependencies when your project actually needs them.

FAQ

Frequently Asked Questions

These are the practical questions beginners usually ask at this stage of the uv workflow.

What is the difference between uv init and creating a folder yourself?

You can create the folder yourself, but uv init gives you a recognized project structure, metadata, a starter file, and Python version pinning immediately.

Why does uv run matter if my script is only one file?

Because it runs the script in the project environment and keeps the project synchronized first. That becomes even more important once you add dependencies.

Should I delete main.py if I want different filenames?

No. You can rename or replace it once you are comfortable. The important part is learning the project workflow, not preserving the starter file forever.

Why does uv.lock appear later instead of immediately?

Because uv creates it when the project actually needs environment resolution, such as during uv run, uv sync, or uv lock.

Do I need to activate .venv right now?

No. You can keep using uv run throughout the series. Activation is optional, not the first thing you need to learn.

Conclusion

At this point, you have a real uv project, and the project layout should already feel less mysterious.

The next skill is the one that makes the project genuinely useful: adding dependencies, syncing the environment, and running code that depends on those packages.

Next in the series

Add Packages and Run Your Project with uv

Raell Dottin

Comments