Rendering huge pull requests in the GitHub Copilot app GitHub rebuilt the pull request view in the GitHub Copilot app to render an open source pull request with 2,200 files, over a million changed lines, and more than 400 inline review comments. The company said the diff surface uses virtualization, typed-array geometry, and an imperative recycled code-row renderer, but that variable-height comments break the "all heights known before paint" contract because a comment's height is only known at render time. GitHub addressed the problem through measurement, a data pipeline, and an instrumented change-measure-improve loop. Rendering huge pull requests in the GitHub Copilot app How we rebuilt the diff surface in the GitHub Copilot app to open a million-line pull request with hundreds of inline review comments. Broad refactors and migrations often have to land as one change. Stacked pull requests https://docs.github.com/pull-requests/how-tos/stacked-pull-requests are a great way to split work into smaller changes, which makes reviews easier and helps teams ship with less risk. But some changes, like this one, can’t be split cleanly. That leaves you with a single pull request that can get very large, and the review conversation causes it to grow. The review experience needs to remain fast and smooth even when the diff and its conversation are enormous. In the GitHub Copilot app https://github.com/features/ai/github-app , we rebuilt the pull request view with that requirement in mind. To see how far that goes, we opened the biggest pull request we could find: an open source one with 2,200 files, over a million changed lines, and more than 400 inline review comments. Here’s how we made even this extreme pull request performant. The scope of the problem Rendering a large diff at speed is well-understood: virtualize the rows, keep the mounted DOM small, and lean on the fact that every row is a line of code at a known height. Comments are the hard part. A comment’s height depends on how its markdown wraps, the expandable sections, whether there’s a reply box in it, and whether its images have loaded yet. You find all of that out at render time. This forces a different architecture. Three problems: 1. Measurement. You can’t know how tall a comment is until you render it. This breaks the design that lets big diffs stay responsive as you scroll. 2. The data pipeline. A fast diff surface is worthless if the data pipeline feeding it stalls, or if it throws away work it already did. 3. How we actually found the bugs. These problems surface under load, on a specific engine, at a specific scroll position. So we defined what healthy meant, instrumented the surface to answer it, and ran the whole change → measure → improve loop unattended. Part 1: Virtualization, and why comments break it The first step is to understand the geometry that makes a code-only diff fast. Once comments enter the picture, that geometry is no longer enough. What makes big diffs fast You cannot put a million DOM nodes on a page. The standard answer is virtualization : mount only the rows that are on screen, plus a small margin, and recycle those same DOM elements as the user scrolls. The list behaves as if all million rows exist. The scrollbar is the right size, scroll-to-row works. But only about 100 rows are ever real at once. For this illusion to hold, something has to supply the geometry. The scrollbar height is the sum of all row heights. The position of row N is the sum of the heights of the rows above it. Jumping to a row, drawing the scrollbar, deciding what’s on screen, it’s all arithmetic over a table of heights. You can build that table from estimates and correct it as rows get measured, and general-purpose variable-height virtualizers do exactly that. But if every row is a line of code at a known font size, you don’t have to. You can compute the whole table up front and it never changes, so there’s nothing to correct later. Call this the “all heights known before paint” contract. Our diff surface is built around it: - An imperative, recycled code-row renderer no React component per row - Typed-array geometry for the offset math - Backend-owned diff documents streamed structure-first - An imperative scroll API with exact “scroll to row N “ None of it scales badly, because no per-frame work grows with the total row count. On pure code this design is the right one, and we kept all of it. How comments change the contract Now put a review thread in the middle of the diff. How tall is it? You don’t know, and you can’t know without rendering it. Its height depends on things that only exist at render time, and they can keep changing after first paint: - Markdown that wraps differently at different widths -