Python + uv + OneDrive: full install & setup (Windows 11)
Goals
You want:
- Your project files (code,
pyproject.toml, docs) in OneDrive for sync/backup. - Your virtual environment and caches outside OneDrive (to avoid sync thrash, file-locking, long paths, and “sync pending” headaches).
uvto manage Python installs and dependencies, with installs landing inC:\Dev\uv-python(or D: if desired).
This guide assumes Windows 11 + PowerShell.
Quick setup: one script
The fastest way to get this setup is one PowerShell script. It works on a fresh PC, and on one that already has Python from several sources (python.org installers, the Microsoft Store, an older uv setup, stray PATH entries): it wipes those and starts clean, which is usually faster than untangling them.
Script: Reset-UvPython.ps1
It removes every Python it can find, then does the manual steps further down for you:
- Inventory: lists python.org installs and the
pylauncher, Store/MSIX Python packages, uv-managed Pythons, shims in.local\bin, leftover folders, and Python entries on PATH. - Remove: runs each installer’s own uninstaller, removes Store packages, runs
uv python uninstall --all, deletes leftover folders (%LOCALAPPDATA%\Programs\Python,%APPDATA%\Python, the pip cache, uv’s AppData Python folder), emptiesC:\Dev\venvs, and cleans PATH. It also clearsPYTHONHOMEandPYTHONPATHif they’re set. - Install: asks which drive should hold the
Devfolder (only if you have more than one fixed drive), installs uv if needed, setsUV_PYTHON_INSTALL_DIRandUV_CACHE_DIR, then installs the latest stable Python (or the version you pass with-Version) and runsuv python update-shell.
At the end it checks whether Windows blocks uv’s python3.<minor>.exe launcher. If it does, the script prints the PATH fix from Troubleshooting.
It does not touch your project folders, Anaconda/Miniconda (it only reports them), or Python that’s bundled inside other apps.
Run it
Download the script (it lands in your Downloads folder), then run it from PowerShell. Use Run as administrator if any Python was installed “for all users”:
cd "$env:USERPROFILE\Downloads"
Unblock-File .\Reset-UvPython.ps1 # clears the "downloaded from internet" flag
powershell -ExecutionPolicy Bypass -File .\Reset-UvPython.ps1 -DryRun # preview only
powershell -ExecutionPolicy Bypass -File .\Reset-UvPython.ps1 # do it (asks you to type YES)
Options:
| Parameter | Default | What it does |
|---|---|---|
-Version |
latest stable | Pin a specific version instead, e.g. -Version 3.13 |
-DevRoot |
ask (see below) | Root for uv-python, uv-cache, venvs, e.g. D:\Dev |
-KeepVenvs |
off | Don’t empty C:\Dev\venvs |
-DryRun |
off | Show what would happen, change nothing |
-Force |
off | Skip the prompts: YES and drive choice (uses the default drive) |
Choosing the drive
If you don’t pass -DevRoot and the PC has more than one fixed drive, the script lists them with their free space and asks which one should hold the Dev folder:
== Which drive should hold the Dev folder?
1) C: Windows 112.4 GB free of 475.8 GB [system, has \Dev, default]
2) D: Data 801.0 GB free of 931.5 GB
Enter a number, or press Enter for C:
The default is the drive that already has a \Dev folder, or C: if none does. With one fixed drive, it uses C:\Dev without asking. Everything in this article that says C:\Dev then means <drive>:\Dev. The script sets UV_PYTHON_INSTALL_DIR and UV_CACHE_DIR to match, and you use the same drive for UV_PROJECT_ENVIRONMENT and the uvenv helper.
If you move to a different drive, the script creates nothing on the old drive. It removes the old uv Python install and cache (wherever UV_PYTHON_INSTALL_DIR and UV_CACHE_DIR pointed) and empties the old venvs folder (unless you pass -KeepVenvs). It deletes the old Dev folder only if that leaves it empty. Projects and anything else there are kept; move those yourself.
After it finishes
- Open a new PowerShell window and run the check the script prints at the end (e.g.
python3.14 --version). - In Settings > Apps > Advanced app settings > App execution aliases, turn off
python.exeandpython3.exe(App Installer) so typingpythondoesn’t open the Microsoft Store. - Rebuild each project’s venv: set
UV_PROJECT_ENVIRONMENT, then runuv sync. - If you use uv tools, rebuild them:
uv tool upgrade --all --reinstall.
Always run
-DryRunfirst. If an uninstaller fails, the script says so. Remove that entry from Settings > Apps and re-run.
Prefer to do it by hand, or want to know exactly what the script sets up? The manual steps follow. After either route, see Workflows for day-to-day use.
Manual setup
Recommended folder layout
Keep the project in OneDrive, but keep the venv + caches + Python installs in a local, non-synced location.
Example:
- Project (synced):
C:\Users\<you>\OneDrive\Projects\myapp\
- Virtualenv root (NOT synced):
C:\Dev\venvs\
- uv cache (NOT synced):
C:\Dev\uv-cache\
- uv managed Python installs (NOT synced):
C:\Dev\uv-python\
Step 1 — Install uv
Option A: Install uv with WinGet
winget install --id=astral-sh.uv -e
Option B: Install uv with Astral’s PowerShell installer
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Verify:
uv --version
uvx --version
Step 2 — Configure uv to install Python in C:\Dev\uv-python
Do this BEFORE running uv python install ....
2.1 Create the directories
New-Item -ItemType Directory -Force C:\Dev\uv-python | Out-Null
New-Item -ItemType Directory -Force C:\Dev\uv-cache | Out-Null
New-Item -ItemType Directory -Force C:\Dev\venvs | Out-Null
2.2 Set persistent env vars (User scope)
[Environment]::SetEnvironmentVariable("UV_PYTHON_INSTALL_DIR", "C:\Dev\uv-python", "User")
[Environment]::SetEnvironmentVariable("UV_CACHE_DIR", "C:\Dev\uv-cache", "User")
Then close PowerShell and open a new window so the variables are loaded.
2.3 Confirm they’re loaded
echo $env:UV_PYTHON_INSTALL_DIR
echo $env:UV_CACHE_DIR
You should see:
C:\Dev\uv-pythonC:\Dev\uv-cache
If you’re in the middle of a session and don’t want to restart, set session vars too:
$env:UV_PYTHON_INSTALL_DIR = "C:\Dev\uv-python" $env:UV_CACHE_DIR = "C:\Dev\uv-cache"
Step 3 — Install Python with uv (and verify the path)
Install the latest stable Python:
uv python install
With no version, uv installs the newest stable CPython it knows about, so this article doesn’t go stale as new versions ship. To pin a specific version instead, name it: uv python install 3.13. You can install several side by side.
Run this outside any project folder. If the current folder has a
.python-versionfile, uv installs that version instead.
Verify it landed in C:\Dev\uv-python:
uv python list
You should see a line with a path like:
C:\Dev\uv-python\cpython-3.<minor>.<patch>-windows-x86_64-none\python.exe
You’ll also see a cpython-3.<minor>-windows-x86_64-none folder. That is a junction uv maintains that points at the newest installed patch of that minor version, so venvs built from it pick up patch upgrades automatically (see Upgrading).
Step 4 — Update PATH so python shims work everywhere
uv python install puts a versioned executable (e.g., python3.14.exe) into:
C:\Users\<you>\.local\bin
If that directory isn’t on PATH, uv will warn.
Plain python / python3 shims are only installed if you add the still-experimental --default flag (uv python install --default). Without it, python resolves to whatever else is on PATH (often the Microsoft Store alias). Inside projects this doesn’t matter — use uv run python.
4.1 Add uv shims to PATH automatically
Run once:
uv python update-shell
Then close PowerShell and open a new one.
Verify (in PowerShell, plain where is an alias for Where-Object, so use where.exe or Get-Command):
uv python list --only-installed # which versions you have
Get-Command python3.* # the versioned executables on PATH
Get-Command python -All # only uv's if you used --default
Then run the versioned one it found, e.g. python3.14 --version.
4.2 If you get “Executable already exists … not managed by uv”
If C:\Users\<you>\.local\bin\python3.<minor>.exe already exists and uv refuses to overwrite it, force replace:
uv python install --force
Step 5 — OneDrive project with an external venv
Assume your OneDrive project folder is:
C:\Users\<you>\OneDrive\Projects\myapp
5.1 Init the project
cd "C:\Users\<you>\OneDrive\Projects\myapp"
uv init
5.2 Put the venv outside OneDrive
Set UV_PROJECT_ENVIRONMENT per project, in the session:
$env:UV_PROJECT_ENVIRONMENT = "C:\Dev\venvs\myapp"
uv sync
uv sync creates the venv if it doesn’t exist, so a separate uv venv isn’t needed.
Don’t set
UV_PROJECT_ENVIRONMENTat User scope. An absolute path is used as-is for every project, so each project’suv syncwould overwrite the same venv (and remove the other projects’ packages). Keep it one path per project, set per session.
Workflows
Two kinds of sessions cover most work: a quick script you write once (or occasionally rerun), and a maintained tool you keep improving and use day to day.
Quick script session
For a single .py file there’s no project and no venv to manage. uv stores the script’s dependencies in the file itself (inline metadata, PEP 723) and builds a throwaway environment in the uv cache (C:\Dev\uv-cache), so nothing lands in OneDrive except the script.
cd "C:\Users\<you>\OneDrive\Projects\scripts"
uv init --script tidy_photos.py # creates the file with a metadata header
uv add --script tidy_photos.py pillow rich # records dependencies in that header
uv run tidy_photos.py # runs it (builds/reuses the cached env)
The top of the file now looks like this:
# /// script
# requires-python = ">=3.<minor>" # the Python you had when you created it
# dependencies = [
# "pillow>=<latest>",
# "rich>=<latest>",
# ]
# ///
Useful extras:
- One-off dependency without editing the file:
uv run --with requests tidy_photos.py - Pin exact versions for later reruns:
uv lock --script tidy_photos.py(writestidy_photos.py.locknext to it) - Edit in VS Code: run
uv sync --script tidy_photos.pyto build the env, thenuv python find --script tidy_photos.pyand paste that path into Python: Select Interpreter
When a script grows a second file, tests, or a settings file, promote it to a tool (below).
Maintained tool session
For something you’ll keep using and changing, make it a real package with a command-line entry point, a lockfile, and dev tools. The source stays in OneDrive; the venv goes in C:\Dev\venvs.
One-time setup:
cd "C:\Users\<you>\OneDrive\Projects"
uv init --package mytool # src\mytool\ layout + [project.scripts] entry point
cd mytool
$env:UV_PROJECT_ENVIRONMENT = "C:\Dev\venvs\mytool" # or run the uvenv helper below
uv add httpx typer # runtime dependencies
uv add --dev pytest ruff # dev-only tools
uv sync
git init; git add .; git commit -m "Initial mytool"
uv init writes a .python-version file pinning the project to the Python minor version you have now. Commit it with pyproject.toml and uv.lock, so the tool doesn’t silently change Python versions under you. There’s no .venv folder to ignore, because it lives outside the project.
Each work session:
cd "C:\Users\<you>\OneDrive\Projects\mytool"
$env:UV_PROJECT_ENVIRONMENT = "C:\Dev\venvs\mytool" # or: uvenv
uv sync # bring the venv in line with uv.lock
uv run mytool --help # run the tool from source
uv run pytest # test
uv run ruff check --fix . # lint
Put it on your PATH for everyday use:
uv tool install --editable . # 'mytool' now works from any folder
--editable means code changes take effect immediately, without reinstalling. Add --force to reinstall after changing dependencies or entry points. The tool gets its own venv under %APPDATA%\uv\tools (outside OneDrive). To keep it with the rest of the layout, set UV_TOOL_DIR to C:\Dev\uv-tools at User scope.
Maintenance:
uv lock --upgrade # move all dependencies to their newest allowed versions
uv sync
uv run pytest # confirm nothing broke, then commit uv.lock
uv build # optional: wheel + sdist in .\dist for sharing
Optional: set the venv path automatically from the folder name
Add this to your PowerShell profile (notepad $PROFILE). Run uvenv from any project folder and it points uv at C:\Dev\venvs\<folder-name>:
function uvenv {
$name = Split-Path -Leaf (Get-Location)
$env:UV_PROJECT_ENVIRONMENT = "C:\Dev\venvs\$name"
Write-Host "UV_PROJECT_ENVIRONMENT = $env:UV_PROJECT_ENVIRONMENT"
}
Upgrading
Python patch releases
uv python upgrade
This moves every installed minor version to its newest patch (e.g. 3.14.x to the latest 3.14.x). It never jumps minor versions. Existing venvs built from the junction follow the upgrade; the old patch is kept for anything still pinned to it.
New minor versions
When a new Python minor version ships (e.g. 3.15), get it the same way you got the first one:
uv python install # now picks the new release; older versions stay installed
uv python list --only-installed
Quick scripts use the newest Python that meets their requires-python, so they move up on their own. Maintained tools stay on the version in .python-version until you move them:
uv python pin 3.15 # updates .python-version
uv sync # rebuilds the venv on the new Python
uv run pytest # confirm, then commit .python-version and uv.lock
Remove an old version once nothing uses it: uv python uninstall 3.13.
uv itself
uv self update # if installed with Astral's installer
winget upgrade --id=astral-sh.uv # if installed with WinGet
Troubleshooting
Python installed into AppData instead of C:\Dev\uv-python
That means UV_PYTHON_INSTALL_DIR wasn’t set in the shell at install time.
Check:
echo $env:UV_PYTHON_INSTALL_DIR
If it’s blank, set it for this session and reinstall:
$env:UV_PYTHON_INSTALL_DIR = "C:\Dev\uv-python"
uv python install
.local\bin warning persists
Run:
uv python update-shell
Then restart PowerShell and re-check:
Get-Command python3.*
where python prints nothing
In PowerShell where is Where-Object, not the Windows where command. Use where.exe or Get-Command.
“An Application Control policy has blocked this file” (os error 4551)
You may see this for C:\Users\<you>\.local\bin\python3.<minor>.exe, for example as a warning from uv python list, or when you run python3.14.
Why: that file is a small launcher uv writes, which hands off to the real python.exe in C:\Dev\uv-python. The launcher is unsigned, and Windows 11 Smart App Control (or an App Control for Business policy) blocks unsigned programs it hasn’t seen before. The real python.exe usually runs fine, so Python itself works and only the shortcut command is blocked. The reset script tests for this at the end and prints the fix below if it applies.
Confirm it:
# Smart App Control: 0 = off, 1 = on, 2 = evaluation
(Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\CI\Policy).VerifiedAndReputablePolicyState
# What Windows blocked
Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" -MaxEvents 30 |
Where-Object Message -like "*python*" | Format-List TimeCreated, Id, Message
Fix (recommended): skip the launcher.
- In projects and scripts, use
uv run python .... It never touches the launcher. - For a bare
pythonat the prompt, put the real install folder (the minor-version junction) on your User PATH:
$dir = "C:\Dev\uv-python\cpython-3.14-windows-x86_64-none" # match your minor version
[Environment]::SetEnvironmentVariable("Path", "$dir;" + [Environment]::GetEnvironmentVariable("Path","User"), "User")
Open a new PowerShell and run python --version. The junction always points to the newest patch of that minor version, so patch upgrades follow along. When you move to a new minor version, change the folder name in PATH. As a bonus, this gives you plain python, not just python3.14.
Also check: commands installed with uv tool install, and tool commands in a venv’s Scripts folder (e.g. pytest.exe), are the same kind of unsigned uv launcher and may be blocked too. If one is, call it as a module instead: uv run python -m pytest.
Alternative: turn off Smart App Control in Windows Security > App & browser control. It can’t make an exception for one file, and on many Windows builds it can’t be turned back on without resetting Windows, so it isn’t worth doing just for a launcher.
References
- uv installation
- uv Python versions (install, upgrade, executables)
- uv project environment configuration (
UV_PROJECT_ENVIRONMENT) - uv releases
- Microsoft OneDrive restrictions and limitations
uv commands and options used here
There’s no man page for uv, but the full option list for any command is built in and always matches your installed version:
uv help python install # long form, every option explained
uv python install --help # same detail
uv python install -h # short summary
Online, the CLI reference covers every command and option, and the environment variable reference covers the UV_* variables. Command names below link to their entry.
| Command | Option | What it does |
|---|---|---|
uv init |
--script |
Create a single-file script with an inline metadata header |
uv init |
--package |
Set up a project to be built as a package (src layout + entry point) |
uv add |
--script <file> |
Add dependencies to a script’s inline metadata instead of a project |
uv add |
--dev |
Add to the development dependency group (test/lint tools) |
uv run |
--with <pkg> |
Run with extra packages installed for this run only |
uv sync |
--script <file> |
Build/update the environment for a script instead of a project |
uv lock |
--script <file> |
Write a lockfile for a script instead of a project |
uv lock |
--upgrade |
Move dependencies to the newest allowed versions, ignoring current pins |
uv tool install |
--editable |
Install your own package so source changes take effect without reinstalling |
uv tool install |
--force |
Reinstall the tool even if it’s already installed |
uv tool upgrade |
--all, --reinstall |
Upgrade every tool and rebuild its packages (after Python changes) |
uv python install |
(no version) | Install the latest stable Python |
uv python install |
--force |
Replace existing Python executables (shims) during installation |
uv python install |
--default |
Experimental: also install plain python / python3 executables |
uv python list |
--only-installed |
Show installed versions only, not downloadable ones |
uv python find |
--script <file> |
Print the interpreter of a script’s environment |
uv python find |
--managed-python |
Only consider uv-managed Pythons (used by the reset script) |
uv python upgrade |
(no version) | Upgrade every installed minor version to its latest patch |
uv python pin |
<version> |
Write .python-version for the project |
uv python uninstall |
--all |
Remove all uv-managed Pythons |
uv python update-shell |
Add the executable directory (.local\bin) to PATH |
|
uv cache clean |
Empty the uv cache | |
uv self update |
Update uv itself (Astral installer installs only) | |
uv build |
Build a wheel and sdist into dist\ |
Global option used by the reset script: --no-cache (-n) uses a temporary cache for that one command, so uv doesn’t create or touch the configured cache folder.
Environment variables used in this article:
| Variable | Purpose |
|---|---|
UV_PYTHON_INSTALL_DIR |
Where uv-managed Pythons are installed (C:\Dev\uv-python) |
UV_CACHE_DIR |
Where the uv cache lives (C:\Dev\uv-cache) |
UV_PROJECT_ENVIRONMENT |
Venv location for the current project (C:\Dev\venvs\<project>); set per session |
UV_TOOL_DIR |
Optional: where uv tool install puts tool environments |