How to configure VS Code for a uv project
VS Code needs three things to work well with a uv project: the right Python interpreterThe program that reads and executes Python code. When you run "python3 hello.py", python3 is the interpreter. , a formatter and linter, and a test runner.
Install the required extensions
Install these extensions from the VS Code marketplace:
The Python extension handles interpreter selection and test discovery. It also installs Pylance (the language server behind IntelliSense and the python.analysis.* settings) and the Python Debugger extension (debugpy) automatically. The Ruff extension provides linting and formatting.
Select the Python interpreter
uv creates a virtual environmentAn isolated folder where Python installs packages for one project, keeping them separate from other projects and your system Python.
Learn more →
in .venv/ at the root of your project. The Python extension detects .venv directories automatically, so in most cases the interpreter is selected without any manual configuration.
Run uv sync to ensure the virtual environment exists. VS Code should pick up the .venv interpreter within a few seconds. If it doesn’t, open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P) and choose Python: Select Interpreter, then pick the interpreter inside .venv.
Tip
If VS Code shows import errors or unresolved modules after adding a dependency with uv add, run uv sync and then reload the VS Code window (Ctrl+Shift+P → Developer: Reload Window). The Python language server needs to re-index the environment.
Configure Ruff for formatting and linting
The Ruff extension replaces both a formatter (like Black) and a linter (like flake8). First add Ruff to the project so the editor and the command line run the same version:
uv add --dev ruffThe extension’s default importStrategy: "fromEnvironment" checks the active interpreter’s environment for a Ruff executable before falling back to its bundled copy. With Ruff installed by uv, the extension uses .venv/bin/ruff (.venv\Scripts\ruff.exe on Windows), so the editor and terminal never drift to different versions.
Then add these settings to .vscode/settings.json:
{
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
}The .ruff suffix on source.fixAll and source.organizeImports scopes each save action to this extension, so neither one triggers another formatter you have installed. The extension reads your project’s pyproject.toml, ruff.toml, or .ruff.toml automatically, so linting rules stay consistent between the editor and the command line.
Note
If you have the older Black Formatter or isort extensions installed, disable them. The Ruff extension handles both tasks.
Set up pytest
The Python extension can discover and run pytest tests from the VS Code sidebar. Add pytest to the project first so the extension finds it in the .venv:
uv add --dev pytestThen add these settings:
{
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": ["tests"]
}Save the file, open the Testing sidebar (beaker icon), and click Refresh Tests. Your test files appear as a tree, each test with a run icon beside it.
Combine the settings in one file
Here is a .vscode/settings.json that combines the Ruff and pytest configurations:
{
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": ["tests"],
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
}
}Commit this file to version control so everyone on the team gets the same formatter and test settings. The interpreter path stays out of it because VS Code auto-detects the .venv directory that uv creates.
Run a file with the play button
The play button (Run Python File) runs your file with the selected interpreter directly. It does not wrap the command in uv run, so it bypasses uv’s dependency resolution for inline script metadata. Run standalone scripts that declare their own dependencies from the integrated terminal with uv run script.py instead. For project code already installed in .venv by uv sync, the play button works fine.
Run Jupyter notebooks
To use Jupyter notebooks in VS Code with a uv project, add ipykernel as a development dependencyA package needed during development (testing, linting, formatting) that is not shipped to users of your project. Installed with the --dev flag.
:
uv add --dev ipykernelOpen a .ipynb file and VS Code will prompt you to select a kernel. Choose the Python interpreter from your .venv directory. If no kernel appears, run uv sync first to ensure ipykernel is installed in the environment.
For more details, see How to run a Jupyter notebook with uv.
Add type checking with ty
ty is Astral’s type checker for Python, built by the same team behind uv and Ruff. The ty VS Code extension (astral-sh.ty) provides type error diagnostics directly in the editor.
Add ty to the project so the editor and the command line agree:
uv add --dev tyLike Ruff, the extension defaults to ty.importStrategy: "fromEnvironment", so it uses the ty in .venv and falls back to its bundled copy only when the environment has none.
Debug with the Python Debugger
With the Python Debugger extension installed, open a Python file and run Python Debugger: Debug Python File from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P). For more control, create a .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
{
"name": "Python: Module",
"type": "debugpy",
"request": "launch",
"module": "your_package",
"console": "integratedTerminal"
}
]
}Replace your_package with your project’s package name. The debugger uses the interpreter from .venv, so it has access to all dependencies installed by uv.
Tip
To debug a single pytest test, right-click the gutter icon next to the test in the editor and choose Debug Test. You can also use the bug icon in the Test Explorer sidebar.
Pick your next step
- Adding type checking? Configure VS Code for type checking in a uv project sets up Pylance or ty.
- Using Cursor instead? Configure Cursor for a uv project covers the same setup for Cursor.
- Working in containers? Use uv with VS Code devcontainers configures remote development.
- Setting up import sorting? Sort Python imports with Ruff organizes imports on save.
Fix common problems
-
“Import could not be resolved” for a third-party dependency. Run
uv syncto install all dependencies, then reload the VS Code window. If the missing import is your own package, skip to Unresolved imports for your own package or a workspace member. -
Wrong Python version. Check that
uv python pinmatches what VS Code shows in the status bar. If they differ, re-select the interpreter from the Command Palette. -
Ruff settings not applied. The Ruff extension reads from
pyproject.tomlorruff.tomlin your project root. Runuv run ruff check .in the terminal to verify the rules match what the extension reports. To confirm the extension loaded the project’s Ruff rather than its bundled copy, run Ruff: Show server logs from the Command Palette; the startup lines print the path to the executable, which should sit inside.venv. -
Unresolved imports for your own package or a workspace member. uv installs your project and its workspace members as editable installs, which leave a
.pthfile in.venv\Lib\site-packages(.venv/lib/python3.x/site-packageson macOS and Linux). Open that file and read the first line.A filesystem path resolves fine, so the fault is elsewhere: run
uv syncand reload the window. A line starting withimportmeans the build backendThe tool that does the actual work of turning your source code into an installable package. Examples include hatchling, setuptools, and uv_build. installed an import hook, the redirection PEP 660 permits. The pyright engine behind Pylance skips.pthlines that begin withimport, so static analysis stops there.uv’s own build backend writes a plain path, so most projects never hit this. When yours does, reinstall the package with
--config-settings editable_mode=compatif it builds with setuptools, which is the only backend that reads that setting; hatchling accepts the flag and ignores it. On any other backend, list the source directory inpython.analysis.extraPaths. Leavepython.analysis.enableEditableInstallsalone: Pylance already defaults it totrue, itsmachinescope means VS Code ignores it in.vscode/settings.json, and Pylance describes it as experimental and for internal use.