mypy vs pyright: Two Checkers, One Pipeline, and a Speed Surprise
mypy catches 57% of type errors by default; pyright catches 97%. But mypy 2.1 now outruns pyright on batch CI. Here is the full 2026 breakdown.

mypy catches 57% of type errors by default; pyright catches 97%. But mypy 2.1 now outruns pyright on batch CI. Here is the full 2026 breakdown.

Pyright wins for new Python projects and VS Code users: it catches 97% of type errors by default and powers Pylance for real-time editor feedback. For Django, SQLAlchemy, and Pydantic-heavy codebases, mypy wins: its plugin ecosystem catches errors pyright misses. And the speed narrative has completely reversed: a June 2026 benchmark shows mypy 2.1.0 running Rich (38K LOC) in 0.90s vs pyright's 2.64s.
The widely-cited "pyright is 3-5x faster" claim predates mypy's mypyc-compiled builds. Pyright checks all code via type inference by default; mypy silently skips unannotated functions unless you add --check-untyped-defs or --strict. That behavioral default explains most of the 40-point error-detection gap between the two tools, which you'll see reflected across performance, type accuracy, editor integration, plugin ecosystem, CI/CD setup, and pricing below.
Feature | mypy | pyright |
|---|---|---|
Best For | Django/SQLAlchemy/Pydantic projects | New projects, VS Code users |
Pricing | Free, open-source (MIT) | Free, open-source (MIT) |
Language | Python + mypyc (C extension) | TypeScript / Node.js |
Batch CI Speed | 0.90s (Rich 38K LOC, June 2026) | 2.64s (same benchmark) |
Typing Spec Conformance | 59.6% (84/141 tests) | 95.7% (135/141 tests) |
Error Detection (default) | 57% (34/60 errors caught) | 97% (58/60 errors caught) |
Editor Integration | dmypy daemon, third-party LSP | Native LSP, powers Pylance |
Plugin Ecosystem | Mature (django-stubs, sqlalchemy-stubs) | Limited (stubs only, no plugin API) |
Unannotated Code | Skipped by default | Checked via inference by default |
CI Installation |
| npm wrapper + Node.js required |
Monthly PyPI Downloads | ~159M | ~35M |
GitHub Stars | 20,489 | 15,482 |

mypy is a static type checker for Python, created in 2012 by Jukka Lehtosalo as a Cambridge PhD project. Dropbox funded its early development (Guido van Rossum joined the mypy team after leaving Google), and it remains the most widely deployed type checker, with ~159M monthly PyPI downloads as of June 2026.
mypy is written in Python and compiled to a C extension via its own mypyc compiler. It uses a multi-pass analysis model: parsing, type collection, and type checking run in sequence, iterating until types converge. By default, mypy skips any function that lacks type annotations: a deliberate design choice for incremental adoption, and the direct source of its 57% default error-catching rate versus pyright's 97%.
[[tool.mypy.overrides]]--check-untyped-defs or --strict, mypy catches only 57% of type errors in partially-annotated codebases
Microsoft built Pyright as a static type checker for Python, releasing it in 2019. Eric Traut (Microsoft Principal Engineer) is the primary maintainer. Pyright ships near-weekly updates (491 total releases since March 2019) and powers Pylance, the official VS Code Python extension with tens of millions of active users.
Pyright is written in TypeScript and runs on Node.js. It uses a lazy JIT evaluation model, computing types on demand, skipping checks not needed in the current context, and re-checking only changed code incrementally. That architecture was designed from the start as a language server foundation, making completions, hover types, go-to-definition, rename refactoring, and auto-imports first-class requirements rather than add-ons.
pyproject.toml; the PyPI package installs a Node.js binary wrapper, complicating pure-Python CI pipelinesThe most repeated claim in Python type-checking circles is wrong. "Pyright is 3-5x faster than mypy" was accurate before mypy's mypyc-compiled builds but no longer holds as of 2026.
A June 2026 benchmark from pydevtools.com (Apple Silicon, median of 5 runs, caches cleared) shows the opposite:
Codebase | mypy 2.1.0 | pyright 1.1.410 |
|---|---|---|
Rich (38K LOC) | 0.90s | 2.64s |
SQLGlot (76K LOC) | 2.58s | 4.04s |
mypy 2.1.0 is 2-3x faster on batch CI runs. This is not a one-off result: an earlier April 2026 run from the same benchmarking project showed the same direction, with mypy outperforming pyright on cold-start batch checks. The --num-workers flag added in mypy 2.0 enables parallel analysis (though real-world speedup on mid-sized projects is ~1.3x, not the 5x cited in release notes for million-line codebases).
The picture is different in editor mode. Pyright's lazy JIT architecture handles incremental re-checks (line-level changes via LSP) in under 100ms; mypy has no native language server, so editor integrations invoke it on save or via dmypy, adding perceptible latency. Result: mypy wins batch CI, pyright wins interactive editor.
At extreme scale, a different story: Charlie Marsh (@charliermarsh) of Astral reported that on a real >15M-line Python codebase, mypy took 38 minutes and pyright crashed out of memory.
During development, we've been running ty over a (real) >15 million line-of-code Python application. On my machine, it completes in about 12.5 seconds. Mypy took 38 minutes. Pyright crashed (ran out of memory).
At 15M lines, both tools show structural limits. For most teams (codebases under 500K lines), mypy wins on batch speed, and pyright wins on editor speed. Call it a tie for overall workflow.
Winner: Tie. mypy wins batch CI (the speed claim has flipped); pyright wins incremental editor. Most teams care about both.
Pyright's correctness advantage is real and substantial, and it starts with a behavioral default most developers don't know about.
The unannotated code gap: by default, mypy skips any function that lacks type annotations, while pyright checks everything via type inference regardless of annotation coverage. On a partially-annotated codebase (which describes the vast majority of real Python projects), mypy silently provides no feedback on that code unless you add --check-untyped-defs or --strict. Pyright does it by default.
In a May 2026 error-detection test (tildalice.io, 60 intentional type errors in an 800-line data-pipeline project), pyright caught 97% (58/60) and mypy caught 57% (34/60). The 40-point gap is almost entirely explained by that default.
Typing spec conformance (python/typing conformance suite, May 2026):
Tool | Tests Passing | Conformance |
|---|---|---|
pyright | 135/141 | 95.7% |
ty (beta) | 95/141 | 67.4% |
mypy | 84/141 | 59.6% |
Pyright passes 95.7% of the official typing spec tests; mypy passes 59.6%. That 36-point gap reflects implementation decisions made before the current spec was formalized, not fundamental design unsoundness. The PEP 484 reference implementation was mypy, but the spec evolved substantially beyond PEP 484, and mypy's implementation hasn't caught up in all areas.
Concrete behavioral disagreements on identical code:
# Missing return statement
def func(x: int) -> int | None:
if x > 0:
return x
# Pyright: 0 errors (correctly infers implicit return None)
# mypy: error: Missing return statement [return]# Variable rebinding with different type
data = ['123', '456']
data = [int(s) for s in data]
# Pyright: 0 errors (narrows data to list[int] after rebinding)
# mypy: error: List comprehension has incompatible type List[int]; expected List[str]Of the major Python type checkers, pyright alone fully understands `new`. A longstanding mypy bug (issue #15182) with `new` return type handling was fixed in May 2026 (post-2.1.0, pending the next release). SymPy's maintainers have been planning to migrate internal CI to pyright while keeping mypy only for checking public API compatibility with downstream libraries.
A FastAPI project benchmark (40K lines, danilchenko.dev) found pyright catching 41 errors vs mypy's 23. All 18 extra pyright errors were real issues in unannotated functions that mypy skipped.
Winner: pyright. The 97% vs 57% default detection rate is the single most important number in this comparison.
Pyright's clearest, least-contested win. It was designed from day one as a language server.
Kyle Bebak at DjangoCon US 2022 put it directly:
"I would go with Pyright. That's the one that I prefer to use. For a couple of reasons. One, Pyright is not only a type checker, it's also a language server... The other point in favor of Pyright is that the author of the library is just a fantastic programmer; he's even the author of a few Python type checking PEPs, some of which have been accepted for inclusion into Python."
Pyright ships as the engine behind Pylance, Microsoft's official Python extension for VS Code. Real-time type errors appear as you type (sub-100ms incremental LSP updates), with hover type information, go-to-definition, find-references, rename refactoring across files, and auto-imports, all without daemon setup. If your team uses VS Code, you are already running pyright via Pylance, whether you chose it or not.
mypy has no official LSP. Editor integrations (pylsp-mypy, vim-mypy) invoke mypy on save (noticeable delay on larger projects) or run dmypy for incremental checks. The experience is rougher: a VS Code user running mypy in CI is running two type models in parallel, seeing different errors in the editor than in the pipeline.
Winner: pyright. The Pylance integration makes this the least close category.
For teams using Django, SQLAlchemy, or Pydantic v1, mypy's plugin ecosystem is the decisive advantage. The accuracy gap here is not cosmetic.
mypy's mature plugin ecosystem:
Field() declarationsPyright has no plugin API for framework-specific patterns: it can use standard .pyi stubs but cannot intercept ORM metaclass type inference the way mypy plugins do, producing real false positives in Django and SQLAlchemy codebases. Kyle Bebak explained the structural lock-in:
"Django-stubs bet heavily on mypy and didn't just create Python type stubs; they created a mypy plugin, which means there's syntax in there that's not compatible with standard type annotations, and other type checkers simply cannot use Django-stubs."
The workaround for pyright on Django projects is django-types, a fork of django-stubs with mypy-specific plugin syntax stripped out. It works but lags django-stubs in coverage and update cadence.
For non-ORM Python (FastAPI without SQLAlchemy, CLI tools, data science pipelines), this distinction matters far less. Pyright's native inference handles most patterns correctly without plugin assistance.
Winner: mypy (for Django/SQLAlchemy/Pydantic v1 projects). pyright (for non-ORM Python).
This is less glamorous than accuracy benchmarks, but it determines which tool your CI pipeline can actually ship.
mypy configuration lives in pyproject.toml, mypy.ini, or setup.cfg. Per-module overrides let you apply different strictness levels across the codebase:
[tool.mypy]
python_version = "3.12"
disallow_untyped_defs = true
check_untyped_defs = true
warn_unused_ignores = true
[[tool.mypy.overrides]]
module = "legacy.*"
ignore_errors = truemypy installs with pip install mypy. No Node.js, no npm, no binary wrapper. u/latkde in r/Python (November 2025) described the practical friction:
"Mypy is great for CI. It's a normal Python package, so super easy to install and configure with conventional Python-oriented tooling. While Pyright is a neat LSP server and tends to run quickly, it's a NodeJS based program and cannot be installed via PyPI... I cannot declare a dependency on Pyright in a pyproject.toml file. I tend to use Pyright a lot for my personal development workflows, but it would take a lot of extra effort to use it as a quality gate."
pyright configuration lives in pyrightconfig.json or pyproject.toml, with four strictness levels: off, basic, standard (default), and strict. The gradation is more accessible for gradual adoption than mypy's binary --strict flag:
{
"typeCheckingMode": "standard",
"reportMissingTypeStubs": "warning",
"useLibraryCodeForTypes": true
}The CI friction is real. Docker-based CI images must provision Node.js separately to run pyright, increasing image size and build times. Some teams work around this by running pyright only in the editor and mypy in CI, which is also the community-endorsed "run both" pattern.
Winner: mypy. pip install mypy simplicity in CI is a genuine advantage, not a trivial concern.
Both tools are free and open-source with no commercial tiers.
Both tools are funded through their respective backers rather than commercial licensing. The community-maintained basedpyright fork (also free) adds a stricter recommended level beyond pyright's strict and enables all rules by default, for teams who want maximum strictness without writing their own config.
Winner: Tie. Neither costs anything.
mypy and pyright are the right frame for 2026. But the speed ceiling is shifting.
Two Rust-based type checkers are starting to change greenfield project recommendations. ty from Astral (OpenAI-backed) claims 10-100x speed over mypy on many projects and reached preview in May 2025. Pyrefly from Meta shipped v1.0 in May 2026 and checks 20M lines of Python in 30 seconds, with 92.2% typing spec conformance. pydevtools.com now recommends Pyrefly for greenfield projects.
Neither is a safe default for most teams yet. ty's 67.4% conformance means real projects will hit edge-case false positives. Pyrefly's plugin ecosystem is immature compared to mypy's.
Neil Mitchell from Meta described PyTorch's migration to Pyrefly as net-zero. The team added a few hundred type: ignore comments during the conversion and removed an equal number.
For teams where CI speed is the primary constraint (codebases above 500K lines, build times measured in minutes), ty and Pyrefly are worth evaluating now. For everyone else, the mypy vs pyright comparison is still the right one to make.
Choose pyright (or basedpyright) if you're starting a new Python project without ORM dependencies, your team uses VS Code with Pylance, or you want 97% default error detection and a built-in LSP.
Choose mypy if your project uses Django, SQLAlchemy, or Pydantic v1; you need a pure-Python CI install with no Node.js; you're adding types to a legacy codebase incrementally; or you publish a PEP 484-compatible library.
Consider running both if you want real-time IDE feedback from pyright/Pylance plus framework-accurate CI gates from mypy with plugins. James Parrott on Python Discuss made the multi-compiler case: "It's best practice in other languages to make sure your code compiles with multiple compilers; multiple type checkers is the Python equivalent."
Oscar Benjamin (SymPy maintainer) describes the split: "I use pyright as an interactive editor plugin whereas mypy is a command line tool."
The downside of running both: # type: ignore silences mypy but not pyright; # pyright: ignore silences pyright but not mypy. Teams using both accumulate dual-ignore comment debt over time. Budget for this if you go that route.

Ruff has overtaken Black in monthly downloads and runs 30x faster. Here is when to switch and when to stay.

uv replaces pip, pyenv, virtualenv, pip-tools, and pipx with one Rust binary. Complete guide to installation, commands, Docker integration, and migration paths.

LangChain wins for stateful multi-agent orchestration and the broadest integration surface. LlamaIndex wins when retrieval accuracy over private documents is th