Typed Python 2025: Mypy + Rust Tools (Ty, Pyrefly) for Error-Free Codebases
For years, Python was the poster child of “move fast and don’t worry about types.” That worked when codebases were a few thousand lines and…
Typed Python 2025: Mypy + Rust Tools (Ty, Pyrefly) for Error-Free Codebases
For years, Python was the poster child of “move fast and don’t worry about types.” That worked when codebases were a few thousand lines and lived in one team’s folder.

🚀 Top Remote Tech Jobs — $50–$120/hr
🔥 Multiple Roles Open — Limited slots! Hiring Experienced Talent (3+ years) Only.
- Frontend / Backend / Full Stack
- Mobile (iOS/Android)
- AI / ML
- DevOps & Cloud
*⏳ *Opportunities Fill FAST — Early Applicants Get Priority! 👉 [Apply Here](https://app.usebraintrust.com/r/code6/)**
Today, Python runs at the core of:
- huge microservice systems
- large monoliths at companies like Instagram and Meta
- complex data platforms and ML infra
- fintech and healthcare backends
In that world, “let’s just rely on tests” is not enough.
Static typing turned from a “nice-to-have” into infrastructure. And in 2025, a new generation of Rust-powered type checkers — especially Ty (by Astral) and Pyrefly (by Meta) — is changing how we do typed Python.
This article shows:
- why typed Python is necessary now
- where
mypystill fits in - what Ty and Pyrefly do differently
- concrete examples of type checking and errors
- how to plug these tools into a real workflow
- where to go deeper with official sources
1. Why Typed Python Matters in 2025
Dynamic typing is fantastic for:
- quick scripts
- one-off automation
- experiments
But in a long-lived, multi-developer codebase, it causes real pain:
- A function that used to return
strnow sometimes returnsNone, and someone finds out only at runtime. - A data structure slowly changes shape (dictionary → object → another object), and half the call sites implicitly break.
- A refactor removes a parameter, but 15 other modules still call the old signature.
- One team expects
Userto haveemail: str, another thinks it can beNone, a third expects a nested object.
Static typing solves a simple but critical problem:
“Can I change this code without breaking everything else?”
Types give you contracts and compile-time feedback.
- IDEs become smarter (jump to definition, refactors, autocomplete).
- Large refactors become safer.
- Cross-team collaboration is easier because interfaces are explicit.
In other words: typing is less about being strict and more about being able to change fast without fear.
2. Mypy: The Workhorse That Built Typed Python
If you’ve worked with typed Python, you’ve probably used mypy.
It did three important things for the ecosystem:
- Proved that static typing for Python was practical.
- Shaped a lot of
typingsemantics (PEP 484 and beyond). - Became the default type checker for many projects.
Simple mypy example
Consider this simple function:
# file: math_utils.py
def add(a, b):
return a + b
This runs fine. But we don’t know:
- whether
aandbare integers, floats, strings, or something else - what type the function returns
Add explicit types:
# file: math_utils.py
from typing import Union
Number = Union[int, float]
def add(a: Number, b: Number) -> Number:
return a + b
Now run mypy:
mypy math_utils.py
If some other file uses it incorrectly:
# file: bad_usage.py
from math_utils import add
result = add("10", 5) # mixing str and int
mypy will report a type error before runtime.
This is already a big win — but as codebases scale into hundreds of thousands or millions of lines, mypy can start to feel slow.
That’s where Rust-based tools come in.
3. Rust Enters the Chat: Why Ty and Pyrefly Exist
Type checking is computationally heavy:
- The checker must parse a lot of files.
- It must track types through imports, inheritance, generics, async flows.
- On big repos, this means thousands of files and complex graphs.
Python itself is not the best language to write that kind of high-performance tool. Rust is.
Rust gives type checkers:
- near-native performance
- memory safety (the tool itself is less likely to crash)
- easy multi-threading and parallelism
That’s why you see a pattern now:
ruff(linter/formatter) → Rustuv(package & env manager) → Rust- Ty → Rust
- Pyrefly → Rust
The idea is simple: keep Python as the language, but use Rust as the engine behind the tooling.
4. Ty: “mypy, But Fast” for Modern Python Projects
Ty is built by Astral, the team behind Ruff and uv. It is a Rust-based static type checker and language server for Python.
The core goal of Ty:
“Give you mypy-like checking at a fraction of the time, so you actually keep typing turned on.”
Installing Ty
If you’re using uv:
uvx ty check
Or via pip:
pip install ty
ty check src/
The check command is the main entry point: it scans your project, reads your type hints, and reports errors.
Example: catching a subtle bug with Ty
Imagine a service layer:
# file: service.py
from typing import TypedDict
class User(TypedDict):
id: int
email: str
def get_email(user: User) -> str:
return user["email"]
Later, someone decides emails can be optional:
class User(TypedDict, total=False):
id: int
email: str
Now email might not exist on a given User. Type checker view:
def get_email(user: User) -> str:
return user["email"] # unsafe now
Ty (like mypy) will now flag:
- either that
emailmay be missing - or that the return type may not always be
str
You can then fix it properly:
from typing import Optional
def get_email(user: User) -> Optional[str]:
return user.get("email")
Ty doesn’t add new type rules here; it just checks them much faster, so you can afford to run it often — in CI and even in pre-commit hooks.
5. Pyrefly: Meta’s Rust-Based Type Checker and Language Server
Pyrefly is Meta’s successor to Pyre: a new type checker and language server written in Rust, designed for large-scale codebases like Instagram’s.
Where Ty focuses on speed and simplicity, Pyrefly also focuses heavily on:
- deep IDE integration
- code navigation
- strictness and correctness for huge repos
You can think of it as:
“A proper compile-time engine for Python, with the UX of a modern language server.”
Installing Pyrefly
pip install pyrefly
pyrefly check src/
For editor use (VS Code, etc.), it also exposes a language server that powers:
- instant error underlines
- go-to-definition
- find references
- rename symbols
- semantic highlighting
Example: strict checking in Pyrefly
Suppose you have a function:
def find_user_email(user_id: int) -> str:
user = fetch_user(user_id)
if not user:
return None
return user.email
This is common in dynamic Python — returning None when something isn’t found—but your type hint says -> str.
A strict checker like Pyrefly will complain:
- “You said you return
str, but you returnedNonealong some paths.”
You then correct the function:
from typing import Optional
def find_user_email(user_id: int) -> Optional[str]:
user = fetch_user(user_id)
if not user:
return None
return user.email
This seems small, but across a large codebase, these small mismatches are exactly what lead to runtime bugs.
6. Putting It All Together: A Typed Python Workflow in 2025
Here’s a realistic way to bring typed Python plus Rust tooling into an existing project.
Step 1: Turn on typing gradually
Start with your public interfaces:
# file: api.py
from typing import Any
def create_user(data: dict[str, Any]) -> dict[str, Any]:
...
Then tighten types over time:
from typing import TypedDict
class CreateUserPayload(TypedDict):
email: str
name: str
class User(TypedDict):
id: int
email: str
name: str
def create_user(data: CreateUserPayload) -> User:
...
Now a type checker knows exactly what goes in and comes out.
Step 2: Keep using mypy if you already have it
If your team already relies on mypy, don’t throw it away. It’s still great as a “truth baseline.”
You can:
- keep
mypyin CI initially - experiment with Ty or Pyrefly locally
- compare speed and diagnostics
Step 3: Drop in Ty for faster feedback
Replace or complement your mypy step:
ty check src/
You’ll likely notice:
- full-project checks are much faster
- incremental runs on changed files feel almost instant
This makes it realistic to:
- run type checks in every PR
- enforce type cleanliness for new code
- treat type errors as CI blockers
Step 4: Add Pyrefly where you care about strictness and IDE experience
If you work on:
- a central platform library
- critical service boundaries
- data pipelines that must not silently break
Set up Pyrefly:
pyrefly check src/
Then:
- configure your IDE to use the Pyrefly language server
- start using go-to-definition, rename, references, etc.
- rely on its diagnostics while editing
For teams at scale, this brings Python closer to the experience of working with TypeScript or Rust: the editor constantly tells you where things do not match your contracts.
7. Code Example: Full Mini-Flow With Types + Checker
Let’s write a small but realistic mini-flow: create a user, store them, and fetch them.
Domain types
# types.py
from typing import TypedDict
class CreateUserPayload(TypedDict):
email: str
name: str
class User(TypedDict):
id: int
email: str
name: str
Repository layer
# repo.py
from typing import Optional
from .types import CreateUserPayload, User
_db: dict[int, User] = {}
_next_id = 1
def create_user(payload: CreateUserPayload) -> User:
global _next_id
user: User = {
"id": _next_id,
"email": payload["email"],
"name": payload["name"],
}
_db[_next_id] = user
_next_id += 1
return user
def get_user(user_id: int) -> Optional[User]:
return _db.get(user_id)
Service layer
# service.py
from typing import Optional
from .types import CreateUserPayload, User
from .repo import create_user, get_user
def register_user(payload: CreateUserPayload) -> User:
# Could add validations here.
return create_user(payload)
def get_user_email(user_id: int) -> Optional[str]:
user = get_user(user_id)
if not user:
return None
return user["email"]
Where type checking helps
- If someone later “simplifies”
CreateUserPayloadto allow missingemailand forgets to updatecreate_user, Ty or Pyrefly will flag that you’re accessingpayload["email"]assuming it exists. - If someone changes
get_userto returnUserinstead ofOptional[User]but leaves the service logic unchanged, the checker will warn about redundantif not userchecks or mismatched return types. - If a caller does:
# elsewhere.py
from .service import register_user
user = register_user({"name": "Alice"}) # missing email
- The type checker can flag that this dict does not match
CreateUserPayload.
In a dynamic world, all of this compiles and fails only at runtime. With strong typing plus a fast checker, you catch it before deploy.
8. How This Changes Your Role as a Python Developer
When you embrace typed Python with fast checkers:
- You spend less time on “stupid” bugs (wrong key, wrong type, missing field).
- Refactors become safer and more frequent.
- Reviews focus more on architecture and logic, not basic correctness.
- Junior developers are guided by the type system, not just code review comments.
Python starts to feel like a high-level language with a real safety net.
You still get:
- expressiveness
- readability
- fast iteration
But now with a Rust-powered guardian watching your contracts.
References and Further Reading
These are good starting points to dive into each tool and concept mentioned above:
- Astral’s announcement and documentation for Ty, a Rust-based Python type checker and language server.
- Astral’s ecosystem overview explaining how Ruff, uv, and Ty fit together for modern Python projects.
- Meta’s engineering posts and official site for Pyrefly, the Rust-powered successor to Pyre, designed to scale to Instagram-sized codebases.
- Pyrefly’s documentation for IDE integration, language-server features, and strict typing modes.
- Comparative articles and community write-ups discussing Ty vs Pyrefly and the broader trend of Rust-based Python tooling.
Thank you for being a part of the community
Before you go:

👉 Be sure to clap and follow the writer ️👏️️
👉 Follow us: **X | [Medium](https://medium.com/codetodeploy)**
👉 CodeToDeploy Tech Community is live on Discord — **Join now!**
👉 Follow our publication, CodeToDeploy
Note: This Post may contain affiliate links.
메타데이터
- post_id
- 641f874d5a9f
- slug
- typed-python-2025-mypy-rust-tools-ty-pyrefly-for-error-free-codebases-641f874d5a9f
- url
- https://medium.com/codetodeploy/typed-python-2025-mypy-rust-tools-ty-pyrefly-for-error-free-codebases-641f874d5a9f
- canonical_url
- https://medium.com/codetodeploy/typed-python-2025-mypy-rust-tools-ty-pyrefly-for-error-free-codebases-641f874d5a9f
- author_url
- https://medium.com/@muruganantham52524
- status
- ok
- fetched_at
- 2026-07-13 12:56:55