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
isinstancechecks,is Noneguards, and similar patterns. - Parallel checking:
pyright --threads <count>splits analysis across worker threads. - Watch mode:
pyright --watchrechecks 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
--verifytypesreports how complete apy.typedpackage’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.
[tool.pyright]
pythonVersion = "3.12"
typeCheckingMode = "standard"
reportMissingTypeStubs = falseThe 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:
{
"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 pyrightneeds 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.