
Stripe’s Developer Productivity team formatted their entire 25-million-line Ruby codebase overnight in 2024 using RubyFmt, a Rust-based autoformatter—one of the largest automated formatting operations ever documented. The codebase has since grown to 42 million lines, all formatted consistently with zero configuration. The diff was so massive GitHub displayed “files changed: infinity.”
Most teams avoid mass reformatting because they fear merge conflict hell and losing git history. Stripe’s success at this scale proves those fears are about execution, not viability. Their engineers now spend zero time on formatting debates, code reviews focus on logic instead of style nits, and the CI/CD pipeline rejects non-formatted code automatically.
How Stripe Formatted 42 Million Lines of Ruby
The initial rollout in 2024 hit 25 million lines across 62,213 files in a single Saturday morning operation. The codebase has grown 68% since then—now 42 million lines—all maintaining consistent formatting through CI/CD enforcement. For context, GitHub couldn’t even render the diff. It literally showed “files changed: infinity” because the changeset exceeded rendering limits.
This scale matters because it challenges the conventional wisdom that “never reformat everything at once.” If Stripe can handle 25 million lines overnight, teams with 100k-1M line codebases have no technical excuse. The tooling exists. The strategy works. The fear is outdated.
Stripe chose an all-at-once approach over incremental rollout. They formatted every Ruby file on a single Saturday morning, creating a clear before/after boundary in git history. This minimized the merge conflict window and avoided the prolonged pain of daily incremental changes. Some in the Hacker News discussion suggested incremental reformatting over two weeks instead. Stripe rejected that—short-term coordination beats prolonged disruption.
Why Rust, Not Ruby: The 100ms Performance Budget
RubyFmt is written in Rust, not Ruby, and that choice is critical. Stripe enforced a strict 100ms latency budget per file for editor integration. Standard Ruby startup takes 158ms. Add Bundler and it hits 345ms. Both exceed the budget before any formatting work even starts.
Stripe’s solution: compile C directly against libruby, eliminating Ruby’s startup overhead entirely. They evolved the architecture over time. Initially, RubyFmt was Ruby-based using the Ripper parser—too slow. They rewrote it in Rust, linked the full Ruby VM into the binary for parse tree access, and implemented direct memory deserialization of Ruby VALUE objects in Rust. The 2025 Prism parser migration eliminated the VM dependency altogether, reducing binary size by megabytes and improving performance further.
For comparison, Clang-format processes 21 million lines of C++ in under six minutes (per a Hacker News comment). Ruby syntax complexity explains some of the difference, but Rust’s 10-100x performance advantage over Ruby-based formatters makes RubyFmt viable where RuboCop fails. Developers complain RuboCop is “still running in background” after other tasks finish. RubyFmt completes before you notice.
Related: Rust ORMs 2026: SQLx vs Diesel vs SeaORM Comparison
The Saturday Morning Rollout: All-At-Once Strategy
Stripe’s rollout happened in four phases. First, they built a per-file opt-in system and started with systems they owned and monitored closely. Second, they expanded coverage gradually, building confidence and creating diffing tools to compare Ripper parse trees before and after formatting. Third came the big flip: they reversed the opt-in model on Saturday morning 2024, formatting all 62,213 files in one operation. Fourth, they burned down remaining exceptions and enforced formatting in CI/CD.
The all-at-once timing was deliberate. Saturday morning minimized active development conflicts. The single operation created a clean git history boundary. And critically, they implemented git blame preservation immediately.
# Add formatting commit hash to .git-blame-ignore-revs at repository root
echo "[full 40-character commit hash]" >> .git-blame-ignore-revs
# Configure git to automatically use it
git config blame.ignoreRevsFile .git-blame-ignore-revs
# GitHub web UI automatically detects this file
Without this, debugging becomes painful—every line of git blame shows the formatting commit instead of actual changes. GitHub automatically detects the ignore file in web-based blame views. Local git needs the config command, but it’s permanent. This isn’t optional. Mass reformatting without git blame preservation destroys the value of version control history. See Rob Allen’s guide on git blame ignore revisions for implementation details.
No Configuration, No Debates: The Zero-Config Win
RubyFmt has zero style configurations. No YAML files, no team debates about tabs versus spaces or line length. One opinionated style enforced across 42 million lines. This contrasts sharply with RuboCop’s extensive configuration options that enable bikeshedding.
Stripe engineers report the impact directly. “It’s really nice not having to waste time giving or receiving PR feedback about simple formatting stuff,” one noted. Another: “Very fast, no discussions on what format to use.” Before RubyFmt, formatting nits ranked among the top 10 developer productivity pain points. After: zero time spent on formatting.
The zero-config philosophy matters because formatting debates are pure waste. Go’s gofmt, Rust’s rustfmt, and Python’s Black all succeed with opinionated, zero-config approaches. Teams that allow configuration invite arguments about every rule. Stripe’s engineers ship features instead of debating brace placement. That’s the cultural shift: give up config control, gain productivity.
What Stripe Gained (and What It Cost)
The gains are clear. Zero formatting discussions. Code reviews focus on logic, not style. Perfect consistency across 42 million lines. Faster onboarding for engineers from languages like Go or Rust where formatters are standard. CI/CD enforcement prevents style drift.
The costs were temporary. Merge conflicts during the Saturday operation required coordination but lasted hours, not weeks. Git blame noise existed until they added the ignore file. Team adjustment to the new style took days, not months. The zero-bugs requirement at this scale was real—0.01% error rate would affect tens of thousands of files—so Stripe ran extensive testing during the opt-in phase.
The ROI calculation is straightforward. Before RubyFmt, engineers wasted time on formatting nits. After RubyFmt, code reviews run 10-20% faster (estimate based on engineer feedback eliminating style discussions). Short-term pain for permanent productivity gains. Stripe’s 68% codebase growth since rollout—25 million to 42 million lines—proves the system scales.
Key Takeaways
- Mass reformatting is viable at any scale—Stripe proves it with 42 million lines of Ruby formatted consistently with zero configuration since 2024
- Tool choice determines success: Rust-based RubyFmt meets the 100ms-per-file performance budget that Ruby-based formatters cannot match
- All-at-once rollout minimizes pain—Stripe’s single Saturday operation created a clean git boundary and avoided prolonged merge conflicts
- Git blame preservation is non-negotiable—use
.git-blame-ignore-revsto maintain version control history usefulness after mass formatting - Zero-config formatters eliminate bikeshedding—opinionated tools like RubyFmt, gofmt, and rustfmt trade configuration control for productivity gains
- Cultural buy-in matters more than technical execution—teams hesitate due to fear of disruption, not actual tooling limitations
For teams considering mass reformatting: Stripe’s playbook works. Choose performant tools, coordinate timing carefully, preserve git history, and enforce consistency going forward. The temporary disruption pays permanent dividends.












