Manual code review and regex-based lint checks⟶LibCST-powered lint framework and Pyre-driven codemods
Instagram's Python server is several million lines, edited by hundreds of engineers shipping hundreds of commits a day. A single shared-state linter couldn't keep up, so they rebuilt static analysis as infrastructure.
Nearly a hundred lint rules broke the one linter meant to run them — so Instagram rebuilt linting as a registry, then taught it to fix code itself.
One visitor, a hundred rules, and no way to tell them apart
Instagram’s server is almost entirely Python, one monolithic codebase of several million lines and a few thousand Django endpoints, all loaded and served together. Hundreds of engineers ship hundreds of commits a day, deployed continuously every seven minutes, with a goal of under an hour between a commit landing and going live. Keeping that pace from devolving into chaos was the whole problem this post is about.
Instagram’s first custom lint rules lived in a single file, sharing a single visitor and shared state. That worked when there were a handful of rules. It stopped working as the rule count grew toward a hundred: the one shared visitor had to know the state and logic of every unrelated check, and it was never clear which state belonged to which rule.
AFTER
A registry, not a monolith, for the linter itself
The fix was a centralized visitor registry, modeled on the pattern JavaScript’s ESLint uses: each lint rule registers which node types it cares about, and the tree traversal calls only the rules that are relevant at each node, skipping the rest. Rules that implement no matching visit method simply never get called for that node, which keeps the cost of adding a new rule low even as the rule count grows.
The payoff shows up directly in the numbers. Instagram usually runs the linter over just the small number of recently changed files, but the redesigned framework can run every custom lint rule, in parallel, over Instagram’s entire server codebase in 26 seconds.
THE BRIDGE
From flagging problems to fixing them automatically
The underlying engine is LibCST, which Instagram built and open-sourced. Where Python’s own ast module throws away comments, parentheses, and spacing during parsing, LibCST keeps a lossless concrete syntax tree while still exposing the semantics a lint rule needs — the best of both representations.
Once lint rules could reliably find a pattern, Instagram layered two more tools on top. Auto-fixers apply a rule’s fix automatically instead of just warning about it, which matters because with “nearly a hundred custom rules,” engineers were starting to tune out lint warnings entirely — what the team calls lint fatigue. Codemods go further still: scriptable, whole-codebase refactors that can retroactively fix every existing violation of a new rule at once, not just the next one a developer happens to write.
WHAT IT COST
Heuristics that are usually right, and honest about when they aren't
None of this is free of judgment calls. The team is explicit that automated return-type inference is a heuristic: it’s “right often enough to be useful,” not guaranteed correct. Inferring a None return type for a function with no explicit return is flagged as riskier than the primitive-type case, since a base-class method might raise NotImplementedError while every real subclass returns a string — a pattern the heuristic can get wrong.
The tradeoff Instagram made deliberately is to prefer proactive, automated fixes over letting deprecated patterns “wither away” on their own, because in a codebase this size, anything left to individual willpower simply doesn’t get cleaned up.
When a codebase outgrows what one linter or one engineer can track by hand, the fix isn’t more diligence — it’s turning the linter itself into infrastructure that can find, fix, and prove out changes at the same scale as the code.
Both are Instagram-scale Python codebases using tooling, not willpower, to keep a huge shared codebase coherent.
A plain-language, AI-drafted and human-edited retelling of the article published on instagram-engineering.com,
reorganized and explained in our own structure and words, with original analysis in the editor's
note above. The facts, numbers, and decisions belong to the original author and are not altered.
For the full depth, read the source.