The Goal: A VS Code Python Environment That Stays Out of Your Way
Visual Studio Code is the most popular editor for Python development in 2026—and for good reason. With the right extensions, settings, virtual environments, and debugger configuration, it rivals PyCharm for daily work while remaining lightweight and free. A default install, however, leaves performance on the table and creates subtle bugs (wrong interpreter, missing type hints, format fights on save).
This guide walks through an optimal setup from scratch: extensions, settings.json, virtual environment workflow, and debugging. Follow it once per machine and you will have a reproducible baseline for any Python project.
Prerequisites
- VS Code 1.90+ (2026 current release)
- Python 3.12 or 3.13 installed system-wide via python.org, Homebrew, or pyenv
- Git for version control integration
- Terminal access (bash, zsh, or PowerShell)
Step 1: Install Essential Extensions
Open VS Code → Extensions (Ctrl+Shift+X) and install the following:
| Extension | Publisher | Purpose |
|---|---|---|
| Python | Microsoft | Core language support, debugging, testing, environment management |
| Pylance | Microsoft | Fast type checking, IntelliSense, auto-imports |
| Python Debugger | Microsoft | Modern debug adapter (replaces legacy debugger in 2025+) |
| Ruff | Astral Software | Linting and formatting (replaces flake8 + black for many teams) |
| Even Better TOML | tamasfe | Syntax highlighting for pyproject.toml |
| GitLens | GitKraken | Inline blame and history (optional but popular) |
Extensions to skip unless you need them
- Jupyter — only if you work in notebooks daily.
- Python Indent — Pylance handles most indentation; can conflict with formatters.
- Multiple formatters — pick Ruff OR Black, not both.
Step 2: Configure settings.json
Open Command Palette (Ctrl+Shift+P) → Preferences: Open User Settings (JSON). Add or merge these settings for a solid Python defaults profile:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
},
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.terminal.activateEnvironment": true,
"python.analysis.typeCheckingMode": "basic",
"python.analysis.autoImportCompletions": true,
"python.analysis.inlayHints.functionReturnTypes": true,
"python.analysis.inlayHints.variableTypes": false,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.rulers": [88, 120]
},
"files.exclude": {
"**/__pycache__": true,
"**/.pytest_cache": true,
"**/.ruff_cache": true,
"**/*.egg-info": true
},
"terminal.integrated.env.linux": {},
"debugpy.debugJustMyCode": true
}
Workspace vs user settings
Put team-shared rules in .vscode/settings.json inside the repo. Keep personal preferences (font, theme) in user settings. Commit .vscode/extensions.json to recommend extensions:
{
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"charliermarsh.ruff"
]
}
Step 3: Virtual Environment Workflow
Never install project dependencies globally. Use a .venv per project—the VS Code Python extension detects it automatically when named conventionally.
Create a new project environment
- Open your project folder in VS Code:
code /path/to/myproject - Open integrated terminal: Ctrl+`
- Create the venv:
python3 -m venv .venv - Activate (Linux/macOS):
Windows PowerShell:source .venv/bin/activate.venv\Scripts\Activate.ps1 - Install dependencies:
pip install --upgrade pip pip install -r requirements.txt # or: pip install -e ".[dev]" for pyproject.toml projects - Select interpreter: Ctrl+Shift+P → Python: Select Interpreter → choose
.venv
pyproject.toml projects (2026 standard)
Modern Python projects use pyproject.toml with uv or pip:
# Install uv (fast package manager, 2026 default for many teams)
curl -LsSf https://astral.sh/uv/install.sh | sh
uv venv
uv pip install -e ".[dev]"
Point VS Code to .venv/bin/python as above. uv creates compatible venvs in seconds.
.gitignore essentials
.venv/
__pycache__/
*.pyc
.pytest_cache/
.ruff_cache/
.env
Step 4: Debugging Configuration
Create .vscode/launch.json for one-click debugging:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "Python: pytest",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": ["-v", "tests/"],
"console": "integratedTerminal",
"justMyCode": false
},
{
"name": "Python: FastAPI",
"type": "debugpy",
"request": "launch",
"module": "uvicorn",
"args": ["main:app", "--reload", "--port", "8000"],
"console": "integratedTerminal",
"justMyCode": true
}
]
}
Debugging walkthrough
- Set a breakpoint by clicking the gutter left of a line number (red dot appears).
- Press F5 or Run → Start Debugging. Select the appropriate configuration.
- When execution pauses, inspect variables in the left panel, hover for values, or use the Debug Console to evaluate expressions.
- Step Over (F10), Step Into (F11), Continue (F5) navigate through code.
- Use conditional breakpoints (right-click breakpoint → Edit Breakpoint) for loop-heavy code.
Worked Example: Setting Up a FastAPI Microservice
mkdir myapi && cd myapi && git init- Create structure:
myapi/ ├── .venv/ ├── .vscode/ │ ├── launch.json │ └── settings.json ├── app/ │ ├── __init__.py │ └── main.py ├── tests/ │ └── test_main.py ├── pyproject.toml └── .gitignore main.pycontains a minimal FastAPI app with one endpoint.- Select
.venvinterpreter; install fastapi, uvicorn, pytest, httpx. - Set breakpoint in the endpoint handler; launch "Python: FastAPI" config; hit the route with curl; inspect
requestobject in debugger. - Run tests with pytest configuration; debug a failing assertion with
justMyCode: falseto step into library code if needed.
Total setup time: under 15 minutes on a clean machine once this guide is familiar.
2026 Version-Specific Notes
- Python 3.13 is production-ready; 3.12 remains the conservative LTS choice for corporate environments. Set
python.analysis.pythonVersionin settings to match your deployment target. - Pylance in 2026 uses improved inference for pandas and pydantic v2—enable
typeCheckingMode: "standard"when your team adopts strict typing. - Ruff now covers 800+ rules and replaces Black, isort, flake8, and pyupgrade in one tool. Configure in
pyproject.toml:[tool.ruff] line-length = 88 target-version = "py312" [tool.ruff.lint] select = ["E", "F", "I", "UP", "B"] - debugpy is the only supported debugger; remove legacy
python.pythonPathsettings from old dotfiles—they are deprecated. - Remote development via Dev Containers is mature: add
.devcontainer/devcontainer.jsonfor identical environments across teammates and CI.
Troubleshooting
Issue 1: "An Invalid Python interpreter is selected"
Cause: Interpreter path points to a deleted venv or system Python missing packages.
Fix: Ctrl+Shift+P → Python: Select Interpreter → Enter interpreter path manually. Recreate .venv if corrupted. Verify which python in terminal matches the selected interpreter (should both show .venv).
Issue 2: IntelliSense is slow or missing imports
Cause: Pylance indexing large monorepos; wrong extraPaths.
Fix: Add "python.analysis.extraPaths": ["./src"] for src-layout projects. Exclude heavy folders: "python.analysis.exclude": ["**/node_modules", "**/.venv"]. Reload window: Developer: Reload Window.
Issue 3: Debugger does not stop at breakpoints
Cause: Running file with "Run Python File" instead of debugger; .pyc-only execution; gevent monkey-patching.
Fix: Always use F5 (debug), not the play button in the corner (which may run without debugpy). Delete __pycache__. For Django/FastAPI, ensure --reload subprocesses are handled—set "subProcess": true in launch.json (debugpy 2025+).
Issue 4: Format on save conflicts or does nothing
Cause: Multiple formatters competing; Ruff not set as default.
Fix: Set editor.defaultFormatter to charliermarsh.ruff under [python]. Disable Black or autopep8 extensions. Check Output panel → Ruff for error messages.
Performance Tips for Large Codebases
- Enable
files.watcherExcludefor.venvanddata/directories. - Use
python.analysis.indexingset to true (default) but limit open files. - Prefer uv over pip for faster environment rebuilds in CI and locally.
- Run tests from terminal in watch mode (
pytest-watch) instead of full IDE test discovery on 10,000+ files.
Testing Integration in VS Code
Testing deserves the same first-class treatment as debugging. With pytest installed in your venv, VS Code discovers tests automatically when files match test_*.py or *_test.py patterns. Open the Testing beaker icon in the sidebar to run individual tests, files, or the full suite with one click.
Add to settings.json for pytest defaults:
{
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": ["tests"]
}
Combine with coverage.py: pytest --cov=app --cov-report=html. Open htmlcov/index.html in a browser. Many teams gate PRs on coverage thresholds—running the same command locally prevents CI surprises.
For monorepos, use a pyrightconfig.json or pyproject.toml [tool.pyright] section to define extra paths per package. VS Code respects these files when Pylance analyzes multi-root workspaces.
With extensions installed, settings tuned, venv workflow habituated, and launch.json committed, VS Code becomes a professional-grade Python IDE. Revisit this checklist when onboarding new machines or teammates—the fifteen minutes of setup pays back on the first debugging session.