# How to configure Cursor for Ruff


Cursor is a fork of VS Code, so the [Ruff](https://pydevtools.com/handbook/reference/ruff.md) extension installs and behaves the same way. The one Cursor-specific difference is the extension source: Cursor uses the [Open VSX Registry](https://open-vsx.org/) instead of the VS Code Marketplace. The extension ID (`charliermarsh.ruff`) is the same.

> [!TIP]
> This guide focuses on Ruff configuration. If you haven't set up your Python interpreter in Cursor yet, start with [How to configure Cursor for a uv project](https://pydevtools.com/handbook/how-to/how-to-configure-cursor-for-a-uv-project.md).

{{< callout type="warning" >}}
This guide assumes you have Cursor installed and a Python project with a virtual environment. Run `uv add --dev ruff` to add Ruff as a project dependency before proceeding.
{{< /callout >}}

## Install the Ruff extension

Open Cursor's extension panel (`Ctrl+Shift+X` / `Cmd+Shift+X`) and search for **Ruff**. Install the extension published by Astral Software (ID: `charliermarsh.ruff`).

If the Black Formatter extension or the isort extension is installed, disable or uninstall them. Ruff covers both tasks; running two formatters on save causes conflicts.

## Configure format-on-save

Create or open `.vscode/settings.json` at the project root and add:

```json {filename=".vscode/settings.json"}
{
    "[python]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.codeActionsOnSave": {
            "source.fixAll.ruff": "explicit",
            "source.organizeImports.ruff": "explicit"
        }
    }
}
```

`source.fixAll.ruff` applies Ruff's auto-fixable lint rules on every save. `source.organizeImports.ruff` sorts imports. The `.ruff` suffix scopes each action to this extension only, so adding another formatter later won't interfere.

Rule selection and other linting settings live in `pyproject.toml`, not in this file. Commit `.vscode/settings.json` so everyone on the project gets the same formatter behavior.

## Use the project's Ruff, not the bundled one

The extension defaults to `importStrategy: "fromEnvironment"`, which looks for Ruff in the active Python environment before falling back to the binary bundled with the extension. Because `uv add --dev ruff` installs Ruff into `.venv`, this default means the editor and `uv run ruff` use the same binary.

No settings change is needed for this to work. The prerequisite is that Ruff is in the project's dev dependencies, not just installed globally.

To confirm which Ruff the editor loaded, open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and run **Ruff: Show server logs**. The output channel shows the path to the Ruff executable on startup. A path under `.venv/` confirms the editor is using the project's version.

## Configure project-level rules

The extension reads `pyproject.toml` (under `[tool.ruff]`), `ruff.toml`, or `.ruff.toml` from the project root. Editor configuration is not needed for rule selection. Add rules to `pyproject.toml`:

```toml {filename="pyproject.toml"}
[tool.ruff.lint]
extend-select = ["I", "UP", "RET", "SIM"]
```

Both the editor and `uv run ruff check .` read the same file, so linting stays consistent between the editor and CI. For a curated starter set, see [How to configure recommended Ruff defaults](https://pydevtools.com/handbook/how-to/how-to-configure-recommended-ruff-defaults.md).

## Troubleshoot common issues

**Extension not formatting on save.** Open Settings and confirm `charliermarsh.ruff` is the default Python formatter. If another formatter extension is active, it may have overridden the setting. Disable any Black Formatter or isort extensions, then reload the window.

**Editor and terminal enforce different rules.** Run **Ruff: Show server logs** to check which binary the editor loaded. If the path is inside the extension directory rather than `.venv/`, run `uv add --dev ruff` to install Ruff in the project environment, then reload the window.

**Ruff not finding your config.** The extension reads config from the project root, not a subdirectory. Open the root folder in Cursor (not a subfolder) so the extension finds `pyproject.toml` or `ruff.toml`.

**Import sorting not working.** Confirm the `I` rule category is enabled in your Ruff config (`extend-select = ["I"]`). If it's in `ignore`, the `source.organizeImports.ruff` action has nothing to sort.

## Learn More

- [Ruff reference](https://pydevtools.com/handbook/reference/ruff.md)
- [How to configure Cursor for a uv project](https://pydevtools.com/handbook/how-to/how-to-configure-cursor-for-a-uv-project.md) for Python interpreter and pytest setup
- [How to configure recommended Ruff defaults](https://pydevtools.com/handbook/how-to/how-to-configure-recommended-ruff-defaults.md) for rule selection
- [How to sort Python imports with Ruff](https://pydevtools.com/handbook/how-to/how-to-sort-python-imports-with-ruff.md)
- [How to migrate from Black to the Ruff formatter](https://pydevtools.com/handbook/how-to/how-to-migrate-from-black-to-ruff-formatter.md)
- [Ruff editor integrations](https://docs.astral.sh/ruff/editors/) (official docs)
- [ruff-vscode repository](https://github.com/astral-sh/ruff-vscode)
