# How to configure mypy strict mode


{{< callout type="warning" >}}
This guide assumes you have a Python project set up with [uv](https://pydevtools.com/handbook/reference/uv.md) and [mypy](https://pydevtools.com/handbook/reference/mypy.md) installed as a dev dependency.
{{< /callout >}}

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](https://pydevtools.com/handbook/reference/pyproject.toml.md):

```toml
[tool.mypy]
strict = true
```

Or pass the flag on the command line:

```bash
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` | Stops `bytearray` and `memoryview` from being assignable to `bytes` (per [PEP 688](https://peps.python.org/pep-0688/)). Default-on in mypy 2.0+ regardless of strict mode. |
| `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](https://mypy.readthedocs.io/en/stable/command_line.html) 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:

```toml
[tool.mypy]
check_untyped_defs = true
disallow_incomplete_defs = true
warn_redundant_casts = true
warn_unused_ignores = true
strict_equality = true
```

Fix 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:

```toml
[tool.mypy]
check_untyped_defs = true

[[tool.mypy.overrides]]
module = ["mypackage.api", "mypackage.api.*"]
strict = true
```

This 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:

```toml
[tool.mypy]
strict = true
warn_return_any = false
```

## Handling 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:

```toml
[[tool.mypy.overrides]]
module = ["some_untyped_library", "some_untyped_library.*"]
ignore_missing_imports = true
```

Check [typeshed](https://github.com/python/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:

```bash
uv add --dev types-requests types-PyYAML
```

## Running mypy with uv

Add mypy as a dev dependency if it is not already present:

```bash
uv add --dev mypy
```

Then run it:

```bash
uv run mypy src/
```

## Related resources

- [mypy reference](https://pydevtools.com/handbook/reference/mypy.md)
- [How do mypy, pyright, and ty compare?](https://pydevtools.com/handbook/explanation/how-do-mypy-pyright-and-ty-compare.md)
- [How to gradually adopt type checking in an existing Python project](https://pydevtools.com/handbook/how-to/how-to-gradually-adopt-type-checking-in-an-existing-python-project.md)
- [How to migrate from mypy to ty](https://pydevtools.com/handbook/how-to/how-to-migrate-from-mypy-to-ty.md)
- [mypy 2.0 picks parallelism over a rewrite](https://pydevtools.com/blog/mypy-2-0-parallel-type-checking.md) covers the `--strict-bytes` default change in mypy 2.0
- [mypy configuration documentation](https://mypy.readthedocs.io/en/stable/config_file.html)
- [mypy --strict flag reference](https://mypy.readthedocs.io/en/stable/existing_code.html)
