Use mypy when you want a mature Python-first checker with broad project adoption and plugin support. Use Pyright when editor feedback and a highly granular strict configuration matter most. Try ty when fast command-line feedback is the priority and its newer ecosystem fits your project. In our pinned Python 3.14 fixture, all three caught the same nine typed-error categories by default; ty had the lowest fresh-process times. That small benchmark measures CLI startup plus three files, not large-project throughput.
Picking a Python type checker is no longer a two-way mypy-versus-Pyright decision. Astral's ty is now a credible third option, and speed claims make it tempting to choose from a benchmark headline alone. That misses the harder questions: do the checkers catch the same mistakes, what changes under strict settings, and which workflow does each one suit?
For this comparison, the same retained fixtures were checked with mypy 2.3.1, Pyright 1.1.413, and ty 0.0.72 on CPython 3.14.2. The test covers bad returns and arguments, None, generics, TypedDict, Protocol, overloads, an unresolved import, an untyped function, valid narrowing, and Python 3.14 template-string syntax. The versions, commands, outputs, timings, and limitations are recorded with the project evidence.
Test setup: same files, pinned versions
The main fixture contains nine intentional typed-error categories plus one valid narrowing function. An unresolved import and a valid Python 3.14 t"..." template string live in separate files, so an import or parser problem cannot prevent the core cases from being checked.
from typing import Protocol, TypedDict, overloaddef bad_return(value: int) -> str:return value # incompatible returnbad_return("wrong") # incompatible argumentmaybe_name: str | None = Nonemaybe_name.upper() # None member accessclass UserRow(TypedDict):name: strage: intmissing_age: UserRow = {"name": "Ada"}class Renderer(Protocol):def render(self, value: int) -> str: ...
| Checker | Pinned version | Default command style |
|---|---|---|
| mypy | 2.3.1 (compiled) | mypy --python-version 3.14 ... |
| Pyright | 1.1.413 (npm) | pyright --pythonversion 3.14 ... |
| ty | 0.0.72 | ty check --python-version 3.14 ... |
For background and installation details, use the official mypy documentation, Pyright documentation, and ty documentation. The result below is our test, not a restatement of any vendor benchmark.
What each checker caught by default
On the deliberately typed cases, the result was a tie: mypy, Pyright, and ty each caught all nine error categories. None complained about the valid union-narrowing function, and all three accepted the separate Python 3.14 template-string file.
| Test category | mypy | Pyright | ty |
|---|---|---|---|
| Wrong return type | Caught | Caught | Caught |
| Wrong argument type | Caught | Caught | Caught |
Access through str | None | Caught | Caught | Caught |
Wrong item in list[int] | Caught | Caught | Caught |
Missing TypedDict key | Caught | Caught | Caught |
Wrong TypedDict value | Caught | Caught | Caught |
Invalid Protocol implementation | Caught | Caught | Caught |
| No matching overload | Caught | Caught | Caught |
| Unresolved import | Caught | Caught | Caught |
| Valid union narrowing | No false positive | No false positive | No false positive |
| Valid Python 3.14 t-string | Accepted | Accepted | Accepted |
Do not compare the raw totals as if a larger number means better checking. mypy and ty produced 9 diagnostics; Pyright produced 10 because it split the single overload mistake into a call error and an argument error. Comparing error categories is more meaningful.
Default versus strict checking
The unannotated function was the useful separator. None of the default runs reported it. mypy --strict raised the total from 9 to 11 by flagging the missing function annotation and the call into untyped code. Pyright strict raised its total from 10 to 17, adding granular unknown parameter, return, and member-type diagnostics.
| Configuration | Diagnostics | What changed |
|---|---|---|
| mypy default | 9 | The nine deliberately typed categories |
mypy --strict | 11 | Also flags the untyped definition and call |
| Pyright default | 10 | Same nine categories; overload issue split in two |
| Pyright strict | 17 | Adds missing and unknown-type diagnostics |
| ty default | 9 | The nine deliberately typed categories |
ty is intentionally not shown with a fake “strict” row. Its current configuration model exposes individual rules and severities rather than one preset directly equivalent to mypy --strict or Pyright typeCheckingMode: "strict". The official mypy/Pyright migration guide for ty explains those differences.
Strict modes exposed the risk of untyped code, but they did not magically infer the runtime failure inside a parameter typed as unknown or Any. Strictness improves annotation coverage; it is not a replacement for tests.
Speed result: ty won this small CLI test
Each default command was started as a new process 11 times against the same three small files on Windows, using an AMD Ryzen 5 3500. The first timed process is separate; the repeated value is the median of the next ten fresh-process runs.
| Checker | First timed process | Repeated median | Repeated range |
|---|---|---|---|
| mypy 2.3.1 | 1268.6 ms | 259.3 ms | 254.6–274.7 ms |
| Pyright 1.1.413 | 594.9 ms | 569.6 ms | 555.4–571.6 ms |
| ty 0.0.72 | 165.5 ms | 55.8 ms | 53.7–60.1 ms |
ty was fastest in this setup: its 55.8 ms repeated median was about 4.6× lower than mypy's and 10.2× lower than Pyright's. That is useful for quick CLI feedback, but it is not evidence that the same ratio holds for your repository. This fixture is tiny, startup dominates, earlier diagnostic runs had already warmed OS caches, and no daemon, editor, or incremental workflow was benchmarked.
mypy: the conservative Python-first choice
mypy is the easiest recommendation when a project already has mypy configuration, plugins, suppressions, and CI history. Its error codes were compact and familiar in this run, and --strict made the move from typed islands to annotation coverage obvious. It is also the checker used by our online Python Type Checker, so a small snippet can be checked without local setup.
Choose mypy when: compatibility with an established Python typing workflow matters more than winning a startup benchmark; your framework depends on a mypy plugin; or the team already understands mypy error codes and configuration.
Pyright: granular strictness and editor-oriented feedback
Pyright produced the most detailed strict output here. That can feel noisy in a migration, but it gives a team precise control over unknown types and incomplete annotations. Its command-line package is installed through npm, and its configuration supports named checking modes plus individual diagnostic rules.
Choose Pyright when: fast editor feedback is central to the workflow, the team wants granular rule-by-rule enforcement, or strict unknown-type reporting is more valuable than the smallest terminal output. If switching from mypy, test the real codebase first—the official comparison documents behavioral differences.
ty: fastest here, with a newer compatibility surface
ty had the lowest startup-inclusive times and still caught every deliberately typed category in our fixture. Its concise messages were readable, and installation can be as simple as pip install ty. The trade-off is not diagnostic ability in this small test; it is project risk. A newer checker may differ on advanced typing behavior, configuration, editor workflows, plugins, and third-party assumptions built around mypy or Pyright.
Choose ty when: very short feedback loops matter, you can validate it against your own repository, and you are comfortable checking compatibility before replacing an established gate. A practical adoption path is to run ty alongside the current checker first, compare disagreements, then decide whether it can become the gate.
Which Python type checker should you use?
| Your priority | Best starting point | Why |
|---|---|---|
| Existing Python project with mypy history or plugins | mypy | Lowest migration cost and mature project conventions |
| Granular strict rules and editor-first workflow | Pyright | Detailed unknown-type diagnostics and configurable modes |
| Fast local CLI feedback | ty | Lowest fresh-process times in this controlled test |
| Learning or checking one snippet in a browser | mypy online | Use the site tool without local installation |
| Large production repository | Benchmark two on your code | Our three-file startup test cannot predict repository behavior |
- Run the candidate checker beside your existing gate; do not replace CI from a generic benchmark.
- Compare disagreements in your hardest modules: framework code, generated code, stubs, overloads, and untyped boundaries.
- Choose a strictness baseline deliberately, then reduce exceptions over time instead of enabling every rule blindly.
- Measure both clean runs and the editor or incremental loop developers actually feel.
For most existing codebases, the best checker is the one that catches useful bugs without causing the team to ignore the gate. Migration cost, false positives, plugins, and editor behavior can outweigh a synthetic speed win.
Reproduce the comparison—and read the limits
mypy --python-version 3.14 --show-error-codes core_cases.py missing_import.py python314_syntax.pymypy --python-version 3.14 --strict --show-error-codes core_cases.py missing_import.py python314_syntax.pypyright --pythonversion 3.14 core_cases.py missing_import.py python314_syntax.pypyright --project pyrightconfig.strict.jsonty check --python-version 3.14 core_cases.py missing_import.py python314_syntax.py
The evidence records exact versions, configuration, diagnostic outputs, all 11 timing samples, and the test machine. The important limits are equally explicit: one Windows machine, three tiny files, startup-heavy fresh processes, warmed OS caches, and no large-project, daemon, incremental, editor, plugin, or third-party-stub benchmark.
Before choosing, replace our fixture with your own modules. If you only need to inspect a function or reproduce a mypy error quickly, open the Python Type Checker. For style and correctness rules outside static typing, use the Ruff Playground as a separate linting step.
Check your annotations now
Paste a typed Python function, run mypy in the browser, and switch on strict mode when you want annotation-coverage checks. No local setup is required.
Open the Python Type CheckerFree tools mentioned here
Related guides
Frequently asked questions
Is ty faster than mypy and Pyright?
It was fastest in our small Windows fresh-process test. ty 0.0.72 had a 55.8 ms repeated median, versus 259.3 ms for mypy 2.3.1 and 569.6 ms for Pyright 1.1.413. This measured CLI startup plus three tiny files, not large-project or incremental performance, so benchmark your own repository before deciding.
Does ty catch the same errors as mypy and Pyright?
For our nine deliberately typed categories, yes: all three caught incompatible returns and arguments, None member access, a generic mismatch, two TypedDict errors, a Protocol mismatch, an overload mismatch, and an unresolved import. That representative fixture does not prove identical behavior for every typing feature or third-party package.
Is Pyright stricter than mypy?
Their strict presets emphasize and count diagnostics differently. In our fixture, mypy strict produced 11 diagnostics and Pyright strict produced 17 because Pyright added several granular unknown parameter, return, and member-type messages. A higher raw count does not automatically mean better checking; compare the actual categories and usefulness on your code.
Does ty have a strict mode like mypy or Pyright?
Not as one directly equivalent preset in the version tested. ty exposes individual diagnostic rules and severities, while mypy provides --strict and Pyright provides typeCheckingMode: strict. Configure the rules you need rather than calling a ty run strict without defining it.
Which Python type checker is best for beginners?
mypy is a practical starting point because its messages, documentation, and examples are widely used, and you can try it in our browser-based checker. Pyright is attractive for editor-first feedback. ty is easy to install and was very fast here, but a beginner should still learn what the reported types mean instead of choosing only by speed.