Skip to content

How do Python type checkers compare?

mypy, pyright, ty, Pyrefly, Basedpyright, and Zuban all analyze type annotations to catch bugs before runtime. They read the same type-hint annotations (from PEP 484, the standard that introduced Python’s type system in 2014) and largely agree on the parts of the spec a working program uses. They disagree on speed, default strictness, treatment of unannotated code, editor integration, and licensing, and those disagreements are what make the choice matter.

Here is the shape of the field in 2026:

Tool Backer Language License First stable
mypy Python community Python MIT 2012
pyright Microsoft TypeScript MIT 2019
Basedpyright DetachHead (fork) TypeScript MIT 2024
ty Astral Rust MIT Beta as of 2026
Pyrefly Meta Rust MIT Beta as of 2026
Zuban David Halter Rust AGPL-3.0 + commercial 2025

How fast each checker runs

The Rust-based checkers (ty, Pyrefly, Zuban) are faster than mypy and pyright on real-world codebases, but the ratio depends heavily on the code and the hardware. The vendor claims are worth knowing and worth treating skeptically:

  • Astral: ty runs 10-100x faster than mypy and pyright
  • Meta: Pyrefly checks Instagram’s 20-million-line codebase in about 30 seconds (roughly 1.85 million lines per second)
  • Zuban: 20-200x faster than mypy

None of these reproduced cleanly in the benchmark table below. The numbers the projects publish come from their own controlled environments, often with specific hardware, parallelism settings, and codebase characteristics the vendor chose. Treat them as plausible upper bounds rather than floors.

Here are timings run on a single Apple Silicon laptop in April 2026. Median of 5 runs, warmup discarded, binaries invoked directly (not through uvx), project-level caches cleared between runs. The mypy column is single-threaded; mypy 2.0 added parallel checking via --num-workers, which the release notes claim delivers up to 5x with 8 workers but is not reflected in this table:

Codebase mypy 1.20 pyright 1.1.408 basedpyright 1.39 ty 0.0.32 Pyrefly 0.62 Zuban 0.7
Rich (38k LOC) 0.88s 2.78s 2.63s 0.13s 0.20s 0.13s
SQLGlot (74k LOC) 2.39s 4.07s 4.49s 3.41s 0.36s 0.49s

Against mypy in this setup:

  • ty: 7x faster on Rich, roughly matches on SQLGlot
  • Pyrefly: 4-7x faster across both, not 35x (Meta’s claim implies ~40x)
  • Zuban: 5-7x faster across both, not 20-200x
  • pyright: 2-3x slower, not “3-5x faster” as older posts report

Two findings are worth drawing out. First, pyright is consistently slower than current mypy. The “3-5x faster” number predates mypy’s mypyc-compiled builds and the 1.18+ optimization work that roughly 40% improved mypy on its own codebase. Basedpyright, as a pyright fork, tracks pyright closely on speed.

Second, ty’s speedup over mypy is not uniform. On normal code (Rich) ty is about 7x faster than mypy. On SQLGlot, which uses heavy @overload chains that stress ty’s inference, ty roughly matches mypy rather than beating it by an order of magnitude. Pyrefly and Zuban do not show this drop-off on SQLGlot. If your code mirrors SQLGlot’s pattern of overload-heavy public APIs, benchmark the tools on your own source before picking one.

mypy 2.0 (May 2026) introduced experimental parallel type checking with --num-workers N, taking a different path from the Rust-rewrite approach. The release notes claim “up to 5x” with 8 workers on large projects, with the speedup depending on import structure and host environment. Re-running the same benchmark on mypy 2.0 with -n 8 on the same hardware shows the much smaller speedup that mid-sized codebases actually see:

Codebase mypy 2.0 (single) mypy 2.0 (-n 8) Speedup
Rich 0.85s 0.66s 1.3x
SQLGlot 2.35s 1.81s 1.3x

Single-process mypy 2.0 is within noise of mypy 1.20. The 5x figure the release notes quote is for “large projects”; Rich and SQLGlot are not large enough to amortize worker startup. Parallel mode also implicitly enables the native parser and still has minor semantic differences from single-process mode. The takeaway: parallel checking helps on million-line codebases, not on the size most projects ship.

How each checker scores on the typing spec

The Python typing community maintains an official conformance test suite that exercises edge cases of the typing spec. Passing more of it means the checker agrees with the spec in more places, which matters when a library’s type stubs rely on a subtle rule. Scores as of March 2026:

Tool Fully passing Pass rate
pyright 136/139 97.8%
Zuban 134/139 96.4%
Pyrefly 122/139 87.8%
mypy 81/139 58.3%
ty 74/139 53.2%

Basedpyright is not scored separately; it inherits pyright’s conformance behavior through frequent rebases.

Conformance is not the same as usefulness. ty’s low score reflects deliberately missing features (the project is in beta and fills them in as it goes), not a flawed type system. mypy’s low score reflects two decades of implementation decisions that predate much of the current spec. Rob Hand’s analysis of the new type checkers argues that the suite tests edge cases most production code never hits, which is worth keeping in mind when reading these numbers.

What happens to code without annotations?

The biggest semantic difference between these tools is how they behave when they encounter code that has no type annotations at all.

mypy skips unannotated functions by default. A function without annotations gets no type checking unless --check-untyped-defs or --strict is enabled. This surprises many users who expect mypy to catch obvious errors in functions they haven’t annotated yet. See how to configure mypy strict mode for the flags that turn this on.

pyright and Basedpyright check all code by default, including unannotated functions, using inferred types. pyright offers five strictness levels (off, basic, standard, strict, all); Basedpyright adds recommended and enables all rules by default.

Pyrefly and Zuban infer aggressively as well. Pyrefly refines types through control-flow analysis and flags problems in untyped code that mypy would skip. Zuban (in zuban check mode) takes a similar aggressive-inference stance.

ty follows a “gradual guarantee”: adding type annotations to working code only narrows existing errors rather than creating new ones. The guarantee is about consistency under annotation; it is not a promise of silence on untyped code. ty still checks everything mypy skips by default, so a previously mypy-clean codebase can surface many new errors under ty. See how to migrate from mypy to ty for the rule categories most teams disable during adoption.

A short example from Posit’s Positron type checker evaluation surfaces the split:

my_list = [1, 2, 3]
my_list.append("foo")

Pyrefly raises bad-argument-type. Basedpyright raises reportArgumentType. Zuban raises arg-type. ty stays silent. mypy’s verdict depends on whether the function is annotated. There is no objectively correct answer here, which is why the tools make different choices.

How editors integrate each checker

pyright has the most polished VS Code experience through the closed-source Pylance extension, which bundles pyright with autocompletion, hover info, go-to-definition, and rename refactoring. Pylance’s license restricts it to official Microsoft VS Code builds, so VS Code forks such as Cursor, VSCodium, and Positron cannot bundle it.

Basedpyright exists in part to fill that gap. It re-implements Pylance-style inlay hints, semantic highlighting, and docstring completion in the open-source language server, and ships on PyPI so editors and CI can pick it up with uv add --dev basedpyright.

ty ships a full LSP implementation with go-to-definition, find references, completions with auto-import, rename refactoring, inlay hints, and signature help. Extensions are available for VS Code, Neovim, Zed, and PyCharm (2025.3+).

Pyrefly ships an LSP with hyperlinked hover docs that surface the source of each inferred type. Positron selected it as their default partly for this reason.

Zuban ships a more basic LSP through zuban server (diagnostics, completions, go-to, references, rename, hover, document highlights). Some features such as inlay hints are not yet implemented.

mypy does not include a language server. Editor integration relies on third-party plugins or IDE-specific implementations. Most developers who use mypy for CI pair it with pyright, Basedpyright, or ty in the editor.

Why licensing and packaging matter

Licensing looks like a footnote until it isn’t. Three cases worth knowing:

Pylance is proprietary. Microsoft’s VS Code extension is free to use in official VS Code but cannot be redistributed or bundled. Teams on VS Code forks (Cursor, VSCodium, Positron, Code-OSS builds) fall back to open-source pyright or Basedpyright.

Zuban is AGPL-3.0 with a commercial option. AGPL’s source-disclosure clause is triggered by network use, which many corporate legal teams will not accept for internal tooling. Zuban sells a commercial license for organizations that need to avoid AGPL. This is a deliberate funding model, not an oversight.

Everyone else is MIT. mypy, pyright (the CLI/LSP, not Pylance), Basedpyright, ty, and Pyrefly are all MIT-licensed and impose no redistribution constraints.

Packaging matters too. pyright ships as an npm package that requires Node.js at runtime; using it in a Python-only CI image means installing Node. Basedpyright, ty, Pyrefly, and Zuban all ship as plain Python wheels on PyPI, which makes uv add --dev <tool> work without extra dependencies.

Where each tool stores its configuration

Tool Config files Table
mypy mypy.ini, .mypy.ini, setup.cfg, pyproject.toml [tool.mypy]
pyright pyrightconfig.json, pyproject.toml [tool.pyright]
Basedpyright pyrightconfig.json, basedpyrightconfig.json, pyproject.toml [tool.basedpyright] (also reads [tool.pyright])
ty ty.toml, pyproject.toml [tool.ty]
Pyrefly pyrefly.toml n/a (no pyproject.toml support)
Zuban mypy.ini, setup.cfg, pyproject.toml (mypy mode); pyproject.toml (check mode) [tool.mypy] in zmypy; [tool.zuban] in zuban check

mypy’s per-module overrides and pyright’s execution environments are useful for monorepos. Pyrefly is the outlier: it does not read pyproject.toml, which complicates co-existence with other tools that do.

How the tools disagree on inference

The tools sometimes disagree on how to infer types for the same code. One notable case: empty containers.

x = []       # What type is x?
x.append(1)

mypy, Pyrefly, and Zuban all infer list[int] by looking at how x is used later in the same scope. pyright, Basedpyright, and ty infer list[Unknown] (semantically equivalent to list[Any]), which is more permissive but less precise.

The practical implication: switching between type checkers can surface new errors or hide existing ones on the same codebase. Treat a migration as a rule-tuning exercise, not a drop-in.

How each project is maintained

mypy has been the default type checker since 2012. Most typing tutorials, blog posts, and Stack Overflow answers reference mypy. Libraries that ship type stubs (via typeshed or standalone packages) test primarily against mypy. Its error codes and suppression comments (# type: ignore[error-code]) are the most widely understood. mypy 2.0 (May 2026) shipped parallel type checking via --num-workers, flipped --local-partial-types and --strict-bytes to default-on, and dropped --python-version 3.9.

pyright has been in active development since 2019 with weekly releases. Microsoft maintains it with dedicated resources, and it often implements new typing PEPs before other checkers.

Basedpyright tracks upstream pyright closely, rebasing on recent pyright releases and shipping on a biweekly cadence. It is the most mature of the non-Microsoft, non-Astral options.

ty entered beta in 2025 and is filling out its typing-spec support on a schedule tracked in a public GitHub issue. Astral’s acquisition by OpenAI in 2026 introduced some uncertainty about the team’s long-term priorities.

Pyrefly launched as open source in 2025. Meta maintains it and uses it internally on Instagram’s codebase, which provides a reliable signal that it handles very large projects.

Zuban launched as open source in September 2025. Development is largely driven by David Halter, who also maintains Jedi, so bus-factor is a real consideration for teams adopting it.

Note

ty, Pyrefly, and Zuban are all new enough that features ship weekly. Verify the current state of each tool against its GitHub repository before relying on benchmarks or feature lists from older articles.

When to choose each

mypy is the safe default for projects that already depend on it. Existing CI pipelines, per-module configuration, and the broadest library compatibility make switching costly for little gain.

pyright is the strongest choice when VS Code and Pylance integration matters, or when aggressive type inference and early PEP support outweigh the risk of extra false positives in dynamic code.

Basedpyright is the better pyright for VS Code forks, teams that need pyright’s analysis as a Python package, and projects that want Pylance-style editor features under an open-source license.

ty fits best where speed is the priority or where a partially-typed codebase needs checking without a flood of false positives. Teams already using Ruff and uv get the benefit of staying within the Astral ecosystem.

Pyrefly suits teams that want aggressive inference and Meta-scale performance on large codebases, and that value its hyperlinked hover documentation. The lack of pyproject.toml configuration is a friction point worth checking before adoption.

Zuban is the right choice for mypy-compatible semantics at Rust-compiled speed, as long as AGPL-3.0 is acceptable or a commercial license is in budget.

Run multiple checkers in parallel

Type annotations are the same across all of these tools, so running pyright or ty in the editor for fast feedback while keeping mypy in CI for library compatibility is a common pattern. Suppression comments differ (# type: ignore for mypy, # pyright: ignore for pyright and Basedpyright, # ty: ignore for ty, # pyrefly: ignore for Pyrefly, # type: ignore for Zuban in mypy mode), so running multiple checkers in CI usually requires maintaining separate suppression comments or tolerating some noise.

Learn More

Last updated on