Skip to content

How do mypy, pyright, and ty compare?

mypy, pyright, and ty all analyze type annotations to catch bugs before runtime. They differ in speed, strictness defaults, and how they handle untyped code.

Speed Comparison

ty runs 10-100x faster than mypy and pyright without caching, and fine-grained incremental analysis makes editor feedback nearly instantaneous. Astral (the team behind Ruff and uv) built ty with the same performance-first philosophy as their other tools.

pyright computes types on demand rather than analyzing everything upfront, making it 3-5x faster than mypy on large codebases. Incremental mode and watch mode provide near-instant feedback during development.

mypy uses a multi-pass architecture that analyzes each module top-to-bottom, repeating until types converge. On large codebases, mypy can take tens of seconds or longer. Recent releases (1.18+) brought roughly 40% performance improvements on mypy’s own codebase.

What Happens to Code Without Annotations?

mypy skips unannotated functions by default. A function without annotations gets no type checking at all 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 details.

pyright checks all code by default, including unannotated functions, using inferred types. It provides five strictness levels (off, basic, standard, strict, all), with standard as the default. pyright infers types aggressively, which catches more bugs but can produce false positives in highly dynamic code.

ty follows a “gradual guarantee” approach. It checks all code but treats unknown types permissively, ensuring that adding type annotations to working code never introduces new errors. This makes ty practical to adopt in large, partially-typed codebases without a flood of false positives.

Configuration

mypy uses mypy.ini, .mypy.ini, setup.cfg, or pyproject.toml (under [tool.mypy]). Configuration supports per-module overrides, which is useful for treating vendored code or test files differently from application code.

pyright uses pyrightconfig.json or pyproject.toml (under [tool.pyright]). It supports execution environments for per-directory settings, letting monorepos configure type checking differently for each package.

ty uses ty.toml or pyproject.toml (under [tool.ty]). Individual diagnostic rules can be set to error, warn, or ignore, with per-file overrides available. User-level configuration lives at ~/.config/ty/ty.toml.

Editor Integration

pyright has the strongest IDE story. Microsoft built it to power the Pylance extension for VS Code, which provides autocompletion, hover information, go-to-definition, and rename refactoring. Pylance is closed-source, but pyright’s open-source language server can be used in other editors.

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+).

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 checking pair it with pyright or ty in their editor.

Ecosystem and Maturity

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 widely understood.

pyright has been in active development since 2019 with weekly releases. Microsoft maintains it with dedicated resources. It often implements new typing PEPs before other checkers, making it the most standards-forward option.

ty entered beta in 2025. It is the newest of the three and still filling out its support for the full Python typing specification. Some features that mypy and pyright handle may not yet be implemented. Astral tracks feature status in a GitHub issue.

Note

ty is in beta. Expect rapid progress, but also missing features and occasional breaking changes between releases.

Type Inference Differences

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

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

mypy infers list[int] by looking at how x is used later. pyright and ty infer list[Any], which is more permissive but less precise. These kinds of differences mean switching between type checkers may surface new errors or hide existing ones.

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.

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.

Running multiple checkers

Type annotations are the same across all three 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, # ty: ignore for ty), so running multiple checkers in CI requires maintaining separate suppression comments.

Learn More

Last updated on

Please submit corrections and feedback...