Skip to main content

Quickstart guide

This guide will get you type checking Python code with mypy in just a few minutes.
Make sure you’ve installed mypy before following this guide.

Your first type-checked program

Let’s start with a simple example to see mypy in action.
1

Create a Python file

Create a file called example.py with the following code:
example.py
def greeting(name):
    return 'Hello ' + name

greeting('World')  # This is fine
greeting(123)      # This will fail at runtime
2

Run mypy without type hints

Try running mypy on this file:
mypy example.py
You’ll see:
Success: no issues found in 1 source file
By default, mypy doesn’t check functions without type annotations. This makes it easy to adopt mypy incrementally.
3

Add type hints

Now let’s add type hints to catch the bug:
example.py
def greeting(name: str) -> str:
    return 'Hello ' + name

greeting('World')  # This is fine
greeting(123)      # Now mypy will catch this!
4

Run mypy with type hints

Run mypy again:
mypy example.py
Now you’ll see an error:
example.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"  [arg-type]
Found 1 error in 1 file (checked 1 source file)
Mypy caught the bug without running the code! This is the power of static type checking.

Understanding type annotations

Type annotations tell mypy (and other readers) what types your code expects:
# The "name: str" says the parameter should be a string
# The "-> str" says the function returns a string
def greeting(name: str) -> str:
    return 'Hello ' + name

Dynamic vs static typing

Mypy distinguishes between dynamically and statically typed functions:
def add(x, y):
    return x + y

# Mypy won't check this, even though it will fail at runtime
add("hello", 123)
You can control this behavior with flags like --disallow-untyped-defs to require type hints on all functions.

Working with complex types

Mypy supports sophisticated type expressions:

Union types

When a value can be one of several types:
def normalize_id(user_id: int | str) -> str:
    if isinstance(user_id, int):
        return f'user-{100_000 + user_id}'
    else:
        return user_id

normalize_id(123)      # OK: returns 'user-100123'
normalize_id('admin')  # OK: returns 'admin'

Optional types

For values that might be None:
def greet(name: str | None = None) -> str:
    if name is None:
        return "Hello, stranger!"
    return f"Hello, {name}!"

greet()          # OK: "Hello, stranger!"
greet("Alice")   # OK: "Hello, Alice!"
On Python 3.9 and earlier, use Optional[str] instead of str | None, or add from __future__ import annotations at the top of your file.

Generic types

For collections with specific item types:
from collections.abc import Iterable

def greet_all(names: Iterable[str]) -> None:
    for name in names:
        print('Hello ' + name)

names = ["Alice", "Bob", "Charlie"]
greet_all(names)   # OK

ages = [10, 20, 30]
greet_all(ages)    # error: List item 0 has incompatible type "int"; expected "str"

Checking multiple files

Mypy can check entire directories:
mypy program.py

Real-world example

Here’s a more complete example showing mypy in action:
user.py
from dataclasses import dataclass

@dataclass
class User:
    name: str
    email: str
    age: int

def create_user(name: str, email: str, age: int) -> User:
    if age < 0:
        raise ValueError("Age cannot be negative")
    return User(name=name, email=email, age=age)

def send_email(user: User, message: str) -> None:
    print(f"Sending to {user.email}: {message}")

# Usage
user = create_user("Alice", "[email protected]", 30)
send_email(user, "Welcome!")

# Mypy catches these errors:
create_user("Bob", "[email protected]", "thirty")  # error: Argument 3 has incompatible type "str"; expected "int"
send_email("not a user", "Hello")  # error: Argument 1 has incompatible type "str"; expected "User"
Run mypy on this file:
mypy user.py
Output:
user.py:19: error: Argument 3 to "create_user" has incompatible type "str"; expected "int"  [arg-type]
user.py:20: error: Argument 1 to "send_email" has incompatible type "str"; expected "User"  [arg-type]
Found 2 errors in 1 file (checked 1 source file)

Daemon mode for faster checking

For large codebases, use daemon mode for much faster incremental checking:
1

Start the daemon

dmypy run -- my_project/
The first run will be slow as it builds the cache.
2

Make changes

Edit your code files.
3

Re-check (much faster)

dmypy run -- my_project/
Subsequent runs are often sub-second, even for large projects.
4

Stop the daemon (optional)

dmypy stop
Daemon mode can provide 10-50x speedup on incremental checks for large codebases.

Configuration file

For project-specific settings, create a mypy.ini or pyproject.toml file:
[mypy]
python_version = 3.10
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True

# Per-module options
[mypy-tests.*]
disallow_untyped_defs = False
Mypy will automatically find and use configuration files in your project directory.

Common flags

Here are some useful command-line flags:
FlagDescription
--strictEnable all optional checks (recommended for new projects)
--disallow-untyped-defsRequire type hints on all functions
--ignore-missing-importsSilently ignore imports of untyped libraries
--show-error-codesShow error codes in output (helpful for filtering)
--prettyUse nicer output with source code snippets
--install-typesAutomatically install missing type stubs
mypy --strict my_project/

Handling third-party libraries

When you import libraries without type hints, mypy will complain:
error: Library stubs not installed for "requests"
note: Hint: "python3 -m pip install types-requests"
You have several options:
1

Install type stubs

Many popular libraries have separate stub packages:
python3 -m pip install types-requests types-PyYAML
Or let mypy install them automatically:
mypy --install-types --non-interactive my_project/
2

Ignore missing imports (per-library)

In your config file:
mypy.ini
[mypy-requests.*]
ignore_missing_imports = True
3

Ignore all missing imports (not recommended)

Use the flag (but this reduces type safety):
mypy --ignore-missing-imports my_project/

Next steps

Now that you know the basics:

Cheat sheet

Quick reference for common type hints and patterns.

Type system reference

Deep dive into mypy’s type system features.

Configuration

Learn about all configuration options.

Common issues

Solutions to frequently encountered problems.

Build docs developers (and LLMs) love