<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax" -->

---
title: Lessons from Pyre that Shaped Pyrefly | daily.dev
description: Meta's Pyrefly team explains design lessons carried over from their earlier Python type checker, Pyre. Key takeaways include the difficulty of retrofitting a...
canonical: https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Lessons from Pyre that Shaped Pyrefly | daily.dev
og:description: Meta's Pyrefly team explains design lessons carried over from their earlier Python type checker, Pyre. Key takeaways include the difficulty of retrofitting a...
og:url: https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax
og:image: https://api.daily.dev/og/posts/B5UU2DUax.png
og:image:alt: Lessons from Pyre that Shaped Pyrefly
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Lessons from Pyre that Shaped Pyrefly

**[Pyrefly: A Fast Python Type Checker and Language Server \| Pyrefly](https://daily.dev/sources/pyrefly)** · 10 min read · 0 upvotes · 0 comments

## Summary

Meta's Pyrefly team explains design lessons carried over from their earlier Python type checker, Pyre. Key takeaways include the difficulty of retrofitting a throughput-oriented CLI tool into a latency-sensitive language server, the decision to switch from OCaml to Rust for cross-platform reliability, the risks of aggressive AST lowering for diagnostic quality, choosing usability over strict soundness for attribute narrowing, and redesigning caching to embrace cyclic dependencies instead of enforcing a strict acyclic phase model. Pyrefly is being built fully in the open, unlike Pyre which started as an internal Meta tool.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://pyrefly.org/blog/lessons-from-pyre>

## Questions this post answers

### Why did Meta switch from OCaml to Rust when building Pyrefly as a successor to Pyre?

Rust treats Windows, macOS, and Linux as equals out of the box, eliminating the cross-platform friction OCaml historically struggled with, especially on Windows. OCaml also relied on a global runtime lock before OCaml 5, forcing Pyre into process-forking and IPC-based parallelism that made shared data structures rigid and algorithmically inflexible. Rust also helped grow the pool of open-source contributors faster.

_daily.dev surfaces language and runtime trade-off writeups for teams weighing a rewrite in Rust._

### Why is Pyre so strict about narrowing an object's attribute type after a function call in Python?

Pyre cannot safely assume a called function won't mutate an attribute like c.x to a different type, either directly or through an alias, so it refuses to narrow the type after such a call. This soundness-first design, rooted in Pyre's security-analysis origins, forced users to rewrite code defensively and was one of the most frequent user complaints; Pyrefly deliberately relaxed this rule for better ergonomics.

_Track how type checkers balance soundness versus usability before picking one for a Python codebase on daily.dev._

### Why was Pyre slow on Python code with heavy use of decorators and descriptors?

Pyre enforced a strictly acyclic, phase-based dependency graph for cache invalidation, meaning computations could only use cached outputs from prior phases, never same-phase or recursive dependencies. Inferring attribute types with descriptors and decorators requires recursive lookups, so Pyre had to recompute intermediate results like method resolution order from scratch instead of reusing cached values, causing major slowdowns on decorator-heavy code.

_Developers debugging type-checker performance on complex codebases can follow these architecture trade-offs on daily.dev._

## Similar posts on daily.dev

- [Pyrefly 1.0: A fast, forward-looking Python linter](https://daily.dev/posts/pyrefly-1-0-a-fast-forward-looking-python-linter-k4vukcqpr) · InfoWorld · 0 upvotes · 0 comments
- [pyre](https://daily.dev/posts/pyre-xlp6zywvb) · Lobsters · 0 upvotes · 0 comments
- [Pyrefly LSP Integration in PyCharm 2026.1.2](https://daily.dev/posts/pyrefly-lsp-integration-in-pycharm-2026-1-2-5vifkrupr) · JetBrains · 4 upvotes · 0 comments
- [Pyrefly Now Type Checks PyTorch – PyTorch](https://daily.dev/posts/pyrefly-now-type-checks-pytorch-pytorch-adohlgdfc) · PyTorch · 0 upvotes · 0 comments

---

Tags: [#general-programming](https://daily.dev/tags/general-programming), [#python](https://daily.dev/tags/python), [#rust](https://daily.dev/tags/rust)

[View this post on daily.dev](https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Lessons from Pyre that Shaped Pyrefly","url":"https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax"},"datePublished":"2026-08-23T12:17:05.718Z","dateModified":"2026-08-23T12:20:06.427Z","description":"Meta's Pyrefly team explains design lessons carried over from their earlier Python type checker, Pyre. Key takeaways include the difficulty of retrofitting a...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/ce7cceb523e1bdb0e6d2d6310d2d101d?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/ce7cceb523e1bdb0e6d2d6310d2d101d?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Pyrefly: A Fast Python Type Checker and Language Server | Pyrefly","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Pyrefly: A Fast Python Type Checker and Language Server | Pyrefly","logo":"https://media.daily.dev/image/upload/s--Qzw5NpnF--/c_limit,w_256/f_auto,q_auto/v1787487420/logos/pyrefly?_a=BAMAMicg0","url":"https://daily.dev/sources/pyrefly"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"general-programming,python,rust","timeRequired":"PT10M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Pyrefly: A Fast Python Type Checker and Language Server | Pyrefly","item":"https://daily.dev/sources/pyrefly"},{"@type":"ListItem","position":3,"name":"Lessons from Pyre that Shaped Pyrefly"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/lessons-from-pyre-that-shaped-pyrefly-b5uu2duax#faq","mainEntity":[{"@type":"Question","name":"Why did Meta switch from OCaml to Rust when building Pyrefly as a successor to Pyre?","acceptedAnswer":{"@type":"Answer","text":"Rust treats Windows, macOS, and Linux as equals out of the box, eliminating the cross-platform friction OCaml historically struggled with, especially on Windows. OCaml also relied on a global runtime lock before OCaml 5, forcing Pyre into process-forking and IPC-based parallelism that made shared data structures rigid and algorithmically inflexible. Rust also helped grow the pool of open-source contributors faster. daily.dev surfaces language and runtime trade-off writeups for teams weighing a rewrite in Rust."}},{"@type":"Question","name":"Why is Pyre so strict about narrowing an object's attribute type after a function call in Python?","acceptedAnswer":{"@type":"Answer","text":"Pyre cannot safely assume a called function won't mutate an attribute like c.x to a different type, either directly or through an alias, so it refuses to narrow the type after such a call. This soundness-first design, rooted in Pyre's security-analysis origins, forced users to rewrite code defensively and was one of the most frequent user complaints; Pyrefly deliberately relaxed this rule for better ergonomics. Track how type checkers balance soundness versus usability before picking one for a Python codebase on daily.dev."}},{"@type":"Question","name":"Why was Pyre slow on Python code with heavy use of decorators and descriptors?","acceptedAnswer":{"@type":"Answer","text":"Pyre enforced a strictly acyclic, phase-based dependency graph for cache invalidation, meaning computations could only use cached outputs from prior phases, never same-phase or recursive dependencies. Inferring attribute types with descriptors and decorators requires recursive lookups, so Pyre had to recompute intermediate results like method resolution order from scratch instead of reusing cached values, causing major slowdowns on decorator-heavy code. Developers debugging type-checker performance on complex codebases can follow these architecture trade-offs on daily.dev."}}]}
```

