# How to configure Cursor for a uv project

{{< callout type="warning" >}}
This guide assumes you have a Python project managed with [uv](https://pydevtools.com/handbook/reference/uv.md). If you haven't created a project yet, see the [project creation tutorial](https://pydevtools.com/handbook/tutorial/create-your-first-python-project.md).
{{< /callout >}}

Cursor is a fork of VS Code, so most Python tooling configuration works the same way. The key difference is Cursor's AI agent, which needs explicit rules to use uv instead of pip. This guide covers both the editor setup and the agent configuration.

## Required extensions

Cursor uses the [Open VSX Registry](https://open-vsx.org/) instead of the VS Code Marketplace. The following extensions are available on Open VSX and can be installed from Cursor's extensions panel:

- [Python](https://open-vsx.org/extension/ms-python/python) (ms-python.python)
- [Ruff](https://open-vsx.org/extension/charliermarsh/ruff) (charliermarsh.ruff)

The Python extension handles interpreter selection and test discovery. It also installs the [Python Debugger extension](https://open-vsx.org/extension/ms-python/debugpy) (debugpy) automatically. The [Ruff](https://pydevtools.com/handbook/reference/ruff.md) extension provides linting and formatting.

> [!NOTE]
> Cursor ships its own language server (`anysphere.cursorpyright`). If installing `ms-python.python` pulls in Pylance, disable Pylance to avoid conflicts with Cursor's built-in language server.

## Select the Python interpreter

uv creates a [virtual environment](https://pydevtools.com/handbook/explanation/what-is-a-virtual-environment.md) in `.venv/` at the root of your project. Cursor detects `.venv` directories automatically, so in most cases the interpreter is selected without manual configuration.

Run `uv sync` to ensure the virtual environment exists. Cursor 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 Cursor shows import errors or unresolved modules after adding a dependency with `uv add`, run `uv sync` and then reload the window (`Ctrl+Shift+P` → **Developer: Reload Window**). The 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). Cursor reads `.vscode/settings.json` for workspace settings, just like VS Code. Add these settings:

```json
{
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.organizeImports.ruff": "explicit"
        }
    }
}
```

This formats Python files on save and organizes imports using Ruff. The extension reads your project's `ruff.toml` or `pyproject.toml` settings automatically, so linting rules stay consistent between the editor and the command line.

## Set up pytest

The Python extension can discover and run [pytest](https://pydevtools.com/handbook/reference/pytest.md) tests from the Testing sidebar. Add these settings to `.vscode/settings.json`:

```json
{
    "python.testing.pytestEnabled": true,
    "python.testing.unittestEnabled": false,
    "python.testing.pytestArgs": ["tests"]
}
```

After saving, open the Testing sidebar (beaker icon) and click **Refresh Tests**. Cursor will discover tests in your `tests/` directory and let you run or debug them individually.

If pytest is a development dependency in your project (`uv add --dev pytest`), Cursor will find it in the `.venv` automatically.

## Complete settings file

Here is a `.vscode/settings.json` that combines all the configurations above:

```json
{
    "python.testing.pytestEnabled": true,
    "python.testing.unittestEnabled": false,
    "python.testing.pytestArgs": ["tests"],
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.organizeImports.ruff": "explicit"
        }
    }
}
```

Commit this file to version control so everyone on the team gets the same formatter and test settings.

## Configure Cursor's AI agent to use uv

Cursor's AI agent does not know about uv by default. Without explicit rules, it will suggest `pip install` and `python` commands instead of `uv add` and `uv run`. Create a `.cursor/rules/` file to fix this.

For a step-by-step walkthrough, see [How to configure Cursor rules to use uv](https://pydevtools.com/handbook/how-to/how-to-configure-cursor-rules-to-use-uv.md).

> [!IMPORTANT]
> When Cursor's agent runs terminal commands, it spawns a fresh shell that may not inherit your activated virtual environment. The agent rules should instruct it to use `uv run` for all Python execution rather than relying on venv activation.

## Running Python files

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](https://packaging.python.org/en/latest/specifications/inline-script-metadata/). For standalone scripts that declare their own dependencies with inline metadata, run them from the integrated terminal with `uv run script.py` instead of the play button.

For project code where dependencies are already installed in `.venv` via `uv sync`, the play button works fine.

## Jupyter notebooks

To use Jupyter notebooks in Cursor with a uv project, add `ipykernel` as a development dependency:

```bash
uv add --dev ipykernel
```

Open a `.ipynb` file and Cursor 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.

> [!TIP]
> Cursor's AI features work better with plain `.py` files than `.ipynb` notebooks. If you want both notebook-style execution and full AI assistance, use `# %%` cell markers in `.py` files. Both Cursor and VS Code support running these as interactive cells.

For more details, see [How to run a Jupyter notebook with uv](https://pydevtools.com/handbook/how-to/jupyter-notebook-with-uv.md).

## Type checking with ty

[ty](https://pydevtools.com/handbook/reference/ty.md) is Astral's type checker for Python, built by the same team behind uv and Ruff. The [ty extension](https://open-vsx.org/extension/astral-sh/ty) (`astral-sh.ty`) is available on Open VSX and provides type error diagnostics directly in the editor.

> [!NOTE]
> ty is in beta. Expect rough edges compared to mature type checkers like [mypy](https://pydevtools.com/handbook/reference/mypy.md) or [pyright](https://pydevtools.com/handbook/reference/pyright.md).

## Debugging

With the [Python Debugger extension](https://open-vsx.org/extension/ms-python/debugpy) installed, open a Python file and run **Python Debugger: Debug Python File** from the Command Palette. For more control, create a `.vscode/launch.json`:

```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.

## Troubleshooting

"Import could not be resolved" warnings: Run `uv sync` to install all dependencies, then reload the Cursor window.

Wrong Python version: Check that `uv python pin` matches what Cursor 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.toml` or `ruff.toml` in your project root. Run `uv run ruff check .` in the terminal to verify the rules match what the extension reports.

Language server conflicts: If you see duplicate diagnostics or unexpected errors, check whether both Pylance and Cursor's built-in `cursorpyright` are active. Disable Pylance and keep the built-in language server.

Agent uses pip instead of uv: Set up `.cursor/rules/` with uv instructions. See [How to configure Cursor rules to use uv](https://pydevtools.com/handbook/how-to/how-to-configure-cursor-rules-to-use-uv.md).

uv workspaces (monorepos): The language server does not fully understand uv workspace structures. Imports between workspace members may show false "unresolved import" warnings. As a workaround, add import paths to `python.analysis.extraPaths` in your workspace settings, or open each workspace member as a separate Cursor window.

## Learn More

- [Cursor Python documentation](https://cursor.com/docs/configuration/languages/python)
- [Cursor extensions](https://cursor.com/docs/configuration/extensions)
- [How to configure Cursor rules to use uv](https://pydevtools.com/handbook/how-to/how-to-configure-cursor-rules-to-use-uv.md)
- [Ruff extension](https://github.com/astral-sh/ruff-vscode)
- [uv reference](https://pydevtools.com/handbook/reference/uv.md)
- [How to install uv](https://pydevtools.com/handbook/how-to/how-to-install-uv.md)
- [pytest tutorial](https://pydevtools.com/handbook/tutorial/setting-up-testing-with-pytest-and-uv.md)
