How to configure mypy strict mode
Running mypy with default settings is lenient. It skips function bodies that lack type annotations and ignores several categories of type errors. Strict mode closes these gaps by requiring annotations on all functions and enabling a curated set of optional checks. The exact flags included in --strict may change between mypy releases.
Enabling strict mode
Add the following to pyproject.toml:
[tool.mypy]
strict = trueOr pass the flag on the command line:
uv run mypy --strict src/What strict mode enables
strict = true is shorthand for enabling these individual flags (as of mypy 1.x):
| Flag | What it does |
|---|---|
disallow_untyped_defs | Requires type annotations on every function definition |
disallow_incomplete_defs | Rejects functions where only some arguments have annotations |
disallow_untyped_calls | Flags calls to functions that lack annotations |
disallow_untyped_decorators | Errors when an untyped decorator is applied to a typed function |
disallow_any_generics | Requires explicit type parameters (e.g., list[int] instead of list) |
disallow_subclassing_any | Prevents subclassing values of type Any |
check_untyped_defs | Type-checks function bodies even without annotations |
warn_return_any | Warns when a function returns a value typed as Any |
warn_unused_configs | Warns about unused [mypy-*] config sections (requires incremental = false to work) |
warn_redundant_casts | Flags unnecessary cast() calls |
warn_unused_ignores | Reports # type: ignore comments that suppress no errors |
strict_equality | Catches comparisons between incompatible types |
strict_bytes | Avoids implicit str-to-bytes coercion in certain checks |
no_implicit_reexport | Requires explicit __all__ or re-import for public names |
extra_checks | Enables additional miscellaneous checks |
Some optional checks like warn_unreachable are not included in --strict. Check the mypy command-line docs for the current list.
Adopting strict mode in an existing codebase
Turning on strict = true in a large existing project usually produces hundreds of errors. A gradual approach works better.
Start with a subset of flags
Instead of enabling everything at once, pick the most impactful flags and add them one at a time:
[tool.mypy]
check_untyped_defs = true
disallow_incomplete_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
strict_equality = trueFix the errors from these, then add more flags until the full set is covered.
Use per-module overrides
Rather than enabling strict mode globally, apply stricter checks only to modules that are already well-typed:
[tool.mypy]
check_untyped_defs = true
[[tool.mypy.overrides]]
module = ["mypackage.api", "mypackage.api.*"]
strict = trueThis enforces strict checking on modules that are ready for it while keeping the rest of the codebase under lighter rules. As you annotate more modules, add them to the override list or move to global strict mode.
Start strict and subtract
For new projects (or projects close to full coverage), enable strict mode and selectively disable flags that cause too much friction:
[tool.mypy]
strict = true
warn_return_any = falseHandling third-party libraries without type stubs
mypy may report import errors for third-party packages that lack type annotations, stubs, or a py.typed marker. This is standard mypy behavior, not specific to strict mode. Silence these per-package:
[[tool.mypy.overrides]]
module = ["some_untyped_library", "some_untyped_library.*"]
ignore_missing_imports = trueCheck typeshed and PyPI for stub packages before suppressing. Many popular libraries have stubs available as separate packages (e.g., types-requests, types-PyYAML). Install them as dev dependencies:
uv add --dev types-requests types-PyYAMLRunning mypy with uv
Add mypy as a dev dependency if it is not already present:
uv add --dev mypyThen run it:
uv run mypy src/Related resources
- mypy reference
- How to migrate from mypy to ty
- mypy configuration documentation
- mypy –strict flag reference