Skip to content

mypy: Python Static Type Checker

mypy is a static type checker for Python that analyzes type annotations to detect bugs before runtime. It supports gradual adoption, per-module configuration, and plugins for libraries whose behavior needs additional type-checker support. Development happens in the python/mypy repository under an MIT license.

When to use mypy

mypy suits projects that need its plugin ecosystem or want to adopt annotations with per-module controls. For editor integration through a language server, consider pyright or ty. The handbook recommends Pyrefly for new projects; a migration should compare diagnostics and plugin requirements first.

For a detailed comparison of all three, see How do mypy, pyright, and ty compare?

Key Features

  • Gradual typing: add type annotations incrementally to an existing codebase. Unannotated functions are skipped by default unless --check-untyped-defs or strict mode is enabled.
  • Type inference: infers variable types from assignments in checked code. Unannotated parameters and function return types remain Any; --check-untyped-defs checks bodies without inferring a typed public signature.
  • Generic types, unions, protocols: supports parameterized types (list[int]), union types (str | int), structural subtyping via Protocol, and TypedDict for typed dictionaries, including closed TypedDicts (PEP 728) that reject undeclared keys.
  • Type stubs: works with typeshed and custom stub files for libraries that don’t ship inline annotations.
  • mypyc compilation: mypy includes mypyc, a compiler that translates type-annotated Python into C extensions for significant runtime speedups.
  • Parallel type checking: pass --num-workers N (short form -n N, or set the MYPY_NUM_WORKERS environment variable) to type-check across multiple worker processes. Parallel mode implicitly enables the native parser.
  • Daemon mode: dmypy keeps a warm server between invocations that caches analysis, so a re-check after an edit skips re-parsing unchanged modules.
  • Native parser: an optional parser based on Ruff’s parser, available via uv add --dev "mypy[native-parser]" and the --native-parser flag.
  • Python 3.14 support: handles t-strings (PEP 750) and ships mypyc-accelerated wheels for free-threading builds.

Pros

  • Plugin support for libraries such as Django through django-stubs
  • Gradual adoption path via per-module configuration overrides
  • mypyc compiler can speed up runtime performance of type-annotated code
  • Parallel checking and incremental caches reduce repeated analysis

Cons

  • Skips unannotated functions by default, which surprises users who expect it to catch obvious errors everywhere (see how to configure mypy strict mode to enable stricter checking)
  • No built-in language server; editor integration relies on third-party plugins or pairing with pyright or ty
  • Struggles with highly dynamic Python patterns

Installation and Usage

# Add as a dev dependency
uv add --dev mypy

# Check a single file
uv run mypy example.py

# Check multiple files or directories
uv run mypy src/ tests/

# Enable stricter checking
uv run mypy --strict example.py

# Type-check in parallel
uv run mypy -n 8 src/

Daemon Mode

dmypy ships with mypy and runs the same checks against a long-lived server process, so the second and later invocations reuse the analysis already in memory:

# Start the daemon and check a path
uv run dmypy run -- src/

# Re-check after an edit; the warm daemon answers without a full restart
uv run dmypy run -- src/

# Shut the daemon down
uv run dmypy stop

The first run prints Daemon started before the diagnostics; subsequent runs print the diagnostics alone. The daemon reads the same [tool.mypy] configuration and reports the same errors as mypy.

Configuration

mypy searches the working directory and its parents, stopping at the repository or filesystem root. In each directory it checks mypy.ini, .mypy.ini, pyproject.toml with [tool.mypy], then setup.cfg with [mypy], in that order. It selects one file without merging; --config-file selects an explicit file. See mypy configuration discovery. The minimum --python-version target is 3.10. --local-partial-types and --strict-bytes (PEP 688) are enabled by default; projects upgrading from 1.x may see new errors from these stricter defaults.

Per-module overrides let you treat vendored code or test files differently from application code:

pyproject.toml
[tool.mypy]
python_version = "3.12"
strict = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false

strict = true enables a bundle of optional checks, including checking untyped bodies and requiring function annotations. The exact bundle can change; inspect mypy --help when upgrading rather than treating it as equivalent to another checker’s strict mode.

Suppressions and Exit Codes

# type: ignore[assignment] suppresses the named mypy error code on one line; bare # type: ignore suppresses every mypy error there. warn_unused_ignores = true reports obsolete suppressions. See mypy error-code controls.

mypy exits with 0 for a successful check, 1 for type-checking errors, and 2 for a serious error such as invalid command-line usage. A clean default run does not establish that unannotated function bodies were checked.

Last updated on