Skip to content

pyright: Python Static Type Checker by Microsoft

pyright is a static type checker and language server for Python, built and maintained by Microsoft. It reads type annotations, infers types for code that has none, and reports mismatches before the code runs.

pyright is written in TypeScript and runs on Node.js. The CLI and language server are MIT-licensed and ship on both PyPI and npm, so uv add --dev pyright works without a separate Node install.

pyright is the default type-analysis engine inside the Pylance extension for Visual Studio Code. Pylance is closed-source and layers autocompletion, signature help, and rename refactoring on top of pyright’s open-source language server.

Evaluate pyright for a project

pyright provides type feedback in the editor, including VS Code through Pylance. Its type inference catches bugs in unannotated code that mypy skips by default.

Teams can keep mypy in CI and use Pylance in the editor; their diagnostics can differ. For the full trade-off table, see How do Python type checkers compare?.

The handbook recommends Pyrefly for new projects. Pylance can also use Pyrefly as its analysis backend through the Type Server Protocol. ty is another alternative; compare the required typing features and diagnostics on project code.

Inspect the analysis features

  • Type inference on unannotated code: pyright checks all code by default, including functions with no annotations, using inferred types. Four strictness levels (off, basic, standard, strict) control how aggressively it reports.
  • Flow analysis: tracks variable types through control flow paths, narrowing types after isinstance checks, is None guards, and similar patterns.
  • Parallel checking: pyright --threads <count> splits analysis across worker threads.
  • Watch mode: pyright --watch rechecks files as they change, giving continuous feedback during development.
  • Typing support: supports Python typing constructs such as generics, protocols, TypedDict, and control-flow narrowing.
  • Type stub integration: works with typeshed and custom stub files, and --verifytypes reports how complete a py.typed package’s public API is.

Configure project checks

pyright reads configuration from pyrightconfig.json or pyproject.toml (under [tool.pyright]). If both exist, pyrightconfig.json takes precedence.

pyproject.toml
[tool.pyright]
pythonVersion = "3.12"
typeCheckingMode = "standard"
reportMissingTypeStubs = false

The typeCheckingMode setting controls overall strictness:

Mode Behavior
off Disables type-checking rules; syntax and semantic diagnostics remain
basic Core type-checking rules
standard CLI default. Enables additional rules beyond basic
strict Reports missing parameter annotations and unknown types; return types can still be inferred

Any other value is rejected with Config "typeCheckingMode" entry must contain "off", "basic", "standard", or "strict"., and pyright falls back to standard. The all and recommended modes documented in some comparisons belong to basedpyright, not pyright.

pyright also supports execution environments for per-directory settings, which is useful for monorepos where different packages need different configurations:

pyrightconfig.json
{
  "executionEnvironments": [
    { "root": "src/backend", "pythonVersion": "3.11" },
    { "root": "src/scripts", "pythonVersion": "3.12" }
  ]
}

Install and run pyright

pyright ships on PyPI, so uv can install and run it with no Node.js setup. The PyPI package uses the node already on PATH and otherwise downloads its own build through nodeenv into ~/.cache/pyright-python the first time it runs.

The quickest way to run pyright is with uvx:

uvx pyright src/

For project use, add pyright as a development dependency:

uv add --dev pyright
uv run pyright src/

uv tool install pyright installs it globally instead, along with the pyright-langserver entry point that editors need.

Diagnostics name the file, position, and rule that fired:

$ uv run pyright src/
src/demo.py
  src/demo.py:5:5 - error: Argument of type "Literal['1']" cannot be assigned to parameter "a" of type "int" in function "add"
    "Literal['1']" is not assignable to "int" (reportArgumentType)
1 error, 0 warnings, 0 informations

Common command-line options:

# Check with a specific config file
pyright --project ./pyrightconfig.json

# Watch mode for continuous checking
pyright --watch

# Split checking across worker threads
pyright --threads 2 src/

# Output as JSON for CI integration
pyright --outputjson src/

Connect an editor

VS Code: install the Pylance extension, which uses pyright by default and adds autocompletion, signature help, auto-imports, and rename refactoring. Pylance also supports Pyrefly as a selectable backend. Pylance is free but closed-source, and its license restricts it to official Microsoft VS Code builds.

Cursor recommends Cursor Pyright, while Positron bundles Pyrefly. Basedpyright provides an open-source alternative for VSCodium and other LSP editors.

Other editors: pyright’s open-source language server works anywhere LSP does. Start it with pyright-langserver --stdio. Neovim users configure it through nvim-lspconfig; Emacs users through Eglot or lsp-mode.

Assess the benefits

  • Checks unannotated code by default, catching bugs that mypy skips
  • VS Code integration through Pylance
  • Granular configuration with per-directory execution environments for monorepos
  • MIT-licensed and published to both PyPI and npm, so uv add --dev pyright needs no separate Node install

Account for the limitations

  • Aggressive inference on unannotated code can produce false positives in highly dynamic code
  • Needs a Node.js runtime, which the PyPI package downloads on first run and which offline or air-gapped CI has to provide up front
  • No plugin API, so the django-stubs and SQLAlchemy plugin behavior mypy users rely on has no equivalent
  • Pylance is closed-source and VS Code-only, so editor features beyond basic LSP do not travel to other editors

Control suppressions and CI failures

Use # pyright: ignore[reportAssignmentType] for a targeted suppression. # type: ignore suppresses all diagnostics on the line, even when its brackets contain another checker’s codes. Enable reportUnnecessaryTypeIgnoreComment to find obsolete ignores. See pyright comment controls.

The CLI exits with 0 when no errors are reported and 1 for errors. Warnings alone exit with 0 unless --warnings is supplied. Fatal errors, unreadable configuration, and invalid arguments use other nonzero codes. See pyright exit codes.

Last updated on