If you use uv on Windows and your projects live in OneDrive, you've probably already run into the problem: OneDrive tries to sync the .venv folder and everything breaks — slow sync, locked files, corrupted environments.
The solution is to centralize virtual environments outside of OneDrive and have uv use them automatically.
The Problem
uv creates the virtual environment inside each project:
OneDrive/
└── dev/
└── my-project/
├── .venv/ ← OneDrive tries to sync this
└── pyproject.toml
A typical .venv folder contains thousands of small files. OneDrive doesn't know to ignore them and syncs everything, causing slowdowns, conflicts, and sometimes corrupted environments.
The Solution
Centralize environments outside of OneDrive using the UV_PROJECT_ENVIRONMENT environment variable:
C:\Users\username\
├── OneDrive\dev\my-project\ ← code, synced by OneDrive
└── .venvs\my-project\ ← environment, outside OneDrive
uv respects UV_PROJECT_ENVIRONMENT and creates the environment wherever you point it.
Setup
1. PowerShell Profile ($PROFILE)
The profile automatically detects whether you're in a uv project and sets the corresponding environment variables:
# ── Workflow ──────────────────────────────────────────────────────
# 1. cd my-project → activates UV_PROJECT_ENVIRONMENT and VIRTUAL_ENV
# 2. uv init → initializes the project
# 3. uv venv → creates environment in ~/.venvs/<project>
# 4. uv add <package> → installs dependencies
# 5. clean-venvs → removes orphaned environments
#
# Notes:
# - Use "cd .." with a space, not "cd.." to clear variables
# - UV_PROJECT_ENVIRONMENT is only set if pyproject.toml exists
# ─────────────────────────────────────────────────────────────────
# ── uv: centralized venvs ────────────────────────────────────────
function Set-UvEnv {
$venvName = Split-Path $PWD -Leaf
$isProject = Test-Path "$PWD\pyproject.toml" -PathType Leaf
if ($venvName -and $isProject) {
$env:UV_PROJECT_ENVIRONMENT = "$env:USERPROFILE\.venvs\$venvName"
$venvPath = "$env:USERPROFILE\.venvs\$venvName"
if (Test-Path $venvPath) {
$env:VIRTUAL_ENV = $venvPath
} else {
$env:VIRTUAL_ENV = $null
}
} else {
$env:UV_PROJECT_ENVIRONMENT = $null
$env:VIRTUAL_ENV = $null
}
}
function Set-LocationWithEnv {
param($Path)
if (-not $Path) { $Path = $env:USERPROFILE }
Set-Location $Path
Set-UvEnv
}
Set-Alias -Name cd -Value Set-LocationWithEnv -Force -Option AllScope
function cddot { Set-LocationWithEnv .. }
Set-Alias -Name 'cd..' -Value cddot -Force -Option AllScope
# Initialize on terminal startup
Set-UvEnv
# uv venv points to centralized directory
function uv {
if ($args[0] -eq 'venv' -and $args.Count -eq 1) {
if (-not (Test-Path "$PWD\pyproject.toml")) {
Write-Host "Run uv init first" -ForegroundColor Yellow
return
}
& (Get-Command uv -CommandType Application) venv $env:UV_PROJECT_ENVIRONMENT
} elseif ($args[0] -eq 'init') {
& (Get-Command uv -CommandType Application) @args
Set-UvEnv
} else {
& (Get-Command uv -CommandType Application) @args
}
}
# Prompt with venv indicator
function prompt {
$venvPath = "$env:USERPROFILE\.venvs\$(Split-Path $PWD -Leaf)"
if (Test-Path $venvPath) {
Write-Host "[ven√] " -NoNewline -ForegroundColor Blue
}
"PS $($PWD)> "
}
# ─────────────────────────────────────────────────────────────────
# ── orphaned environment cleanup ─────────────────────────────────
function Remove-OrphanEnvs {
$venvs = Get-ChildItem "$env:USERPROFILE\.venvs" -Directory
foreach ($venv in $venvs) {
$projectPath = "$env:USERPROFILE\OneDrive\dev\$($venv.Name)"
if (-not (Test-Path "$projectPath\pyproject.toml")) {
Write-Host "Orphan: $($venv.Name)" -ForegroundColor Yellow
$confirm = Read-Host "Delete? (y/n)"
if ($confirm -eq "y") {
Remove-Item -Recurse -Force $venv.FullName
Write-Host "Deleted" -ForegroundColor Red
}
}
}
}
Set-Alias -Name clean-venvs -Value Remove-OrphanEnvs
# ─────────────────────────────────────────────────────────────────
Adjust the path
$env:USERPROFILE\OneDrive\devinRemove-OrphanEnvsto wherever your projects live.
2. VS Code (settings.json)
"python.venvPath": "~/.venvs",
"python-envs.terminal.autoActivationType": "off",
"python.useEnvironmentsExtension": true,
python.venvPath tells VS Code where to look for environments for IntelliSense and the interpreter selector. autoActivationType: off disables VS Code's automatic activation, since the PowerShell profile handles that.
How It Works
Navigating into a project
cd my-project
The cd alias calls Set-UvEnv, which checks whether pyproject.toml exists in the folder. If it does, it sets UV_PROJECT_ENVIRONMENT and VIRTUAL_ENV pointing to ~/.venvs/my-project. The prompt shows [venv√] if the environment has already been created.
Leaving a project
cd ..
Set-UvEnv detects that the new folder has no pyproject.toml and clears both variables. uv stops pointing to the previous environment.
Full workflow for a new project
cd my-project # activates UV_PROJECT_ENVIRONMENT
uv init # creates pyproject.toml and updates variables automatically
uv venv # creates the environment in ~/.venvs/my-project
uv add pandas # installs dependencies into the centralized environment
If you try uv venv before uv init, the profile shows a warning:
Run uv init first
Cleaning up orphaned environments
When you delete a project, its environment in ~/.venvs becomes orphaned. To clean it up:
clean-venvs
The script iterates over ~/.venvs, finds environments with no corresponding project, and asks before deleting each one.
Design Decisions
Why validate pyproject.toml instead of just the folder name?
Without that check, UV_PROJECT_ENVIRONMENT would be set for any folder, including system folders. If the terminal opens in C:\Windows\System32, for example, it would create ~/.venvs/System32.
Why is VIRTUAL_ENV only set if the environment already exists?
VS Code reads VIRTUAL_ENV to detect the interpreter. If it points to a non-existent path, VS Code may show errors or fail to detect the environment correctly when creating a new project.
Why the cd.. alias in addition to cd?
PowerShell allows writing cd.. without a space, but in that case it bypasses aliases and runs the native command, without calling Set-UvEnv. The explicit cd.. alias ensures variables are also cleared in that case.
Limitations
This solution assumes the project folder name matches the environment name in ~/.venvs. If you have projects with duplicate names in different subfolders of OneDrive, there may be collisions.
It also requires the profile to be installed on every machine you work on. It's portable — no external dependencies — but it is a manual step when setting up a new machine.
Top comments (0)