A developer's desk in dim natural light, code barely visible on monitor screen
Issue 14 · February 2026 · Frontend Engineering

The RenderingPipelineHas No Secrets.

This month: every decision React makes between your JSX and the DOM — reconciliation heuristics, fiber scheduling, concurrent features, and why your profiler numbers still don't tell the full story.

Scroll to read
Issue 14 · Contents

What's Inside

01
What the Browser Actually DoesThe gap between your mental model and the spec is where bugs live.
02
Fiber Is Not a Data StructureIt's a scheduling protocol. Understanding this changes everything.
03
Concurrent Mode's Hidden CostWhy enabling Concurrent Mode on a legacy codebase is a trap.
04
Profiling Without IllusionsDevTools lie. Here's how to read the timeline without being misled.

Plus: 3 annotated code walkthroughs, 2 architecture diagrams, and one very opinionated take on React Server Components.

Chapter 01 · Excerpt

"The layout phase isn't where your slowdown lives. It's the three forced reflows you triggered before you got there."

What the Browser Actually Does

Most engineers have a working model of the browser's rendering pipeline. Parse HTML → build DOM → apply styles → layout → paint → composite. It's accurate enough to build products, and imprecise enough to produce performance bugs that take days to diagnose.

The model fails at the boundaries. When you call getBoundingClientRect() inside a scroll handler, you're not reading a cached value — you're synchronously forcing layout recalculation on whatever subtree the browser considers dirty. The cost isn't the function call. The cost is everything that happens before the function can return.

Understanding the pipeline at this level of specificity changes how you read profiler output. The flame chart stops being a timeline of function calls and starts being a map of causality. You stop asking "what's slow" and start asking"what forced this."

The Forced Reflow Pattern
<span class="code-token-comment">// ❌ Triggers layout recalculation on every scroll tick</span>
<span class="code-token-keyword">function</span> <span class="code-token-fn">onScroll</span>() {
  <span class="code-token-keyword">const</span> items = document.<span class="code-token-fn">querySelectorAll</span>(<span class="code-token-string">'.item'</span>);
  items.<span class="code-token-fn">forEach</span>(item => {
    <span class="code-token-keyword">const</span> rect = item.<span class="code-token-fn">getBoundingClientRect</span>(); <span class="code-token-comment">// forced reflow</span>
    item.style.transform = <span class="code-token-string">`translateY(${rect.top * 0.1}px)`</span>; <span class="code-token-comment">// invalidates layout</span>
  });
}

<span class="code-token-comment">// ✓ Read all, then write all — one layout pass</span>
<span class="code-token-keyword">function</span> <span class="code-token-fn">onScrollOptimized</span>() {
  <span class="code-token-keyword">const</span> items = document.<span class="code-token-fn">querySelectorAll</span>(<span class="code-token-string">'.item'</span>);
  <span class="code-token-keyword">const</span> rects = [...items].<span class="code-token-fn">map</span>(el => el.<span class="code-token-fn">getBoundingClientRect</span>());
  items.<span class="code-token-fn">forEach</span>((item, i) => {
    item.style.transform = <span class="code-token-string">`translateY(${rects[i].top * 0.1}px)`</span>;
  });
}
2,847

engineers read last month's issue on partial hydration

Issue 13 · January 2026 · The most-shared Frontmatter issue to date

Chapter 02 · Excerpt

Fiber Is Not a Data Structure

It's a scheduling protocol. Understanding this changes everything about how you reason about component re-renders, priority queues, and why startTransition does what it does.

Fiber Work Loop — SimplifiedFig. 2.1
scheduleUpdateenqueue work unitperformWorkrender phase (interruptible)commitWorkcommit phase (synchronous)DOMpaintedcan be interrupted

React 18's concurrent features aren't a new rendering engine. They're a new scheduling layer on top of the same fiber work loop that shipped in React 16. The distinction matters because it tells you exactly what concurrent mode can and cannot do.

The render phase — where React calls your component functions and diffs the virtual DOM — has always been pure computation. Fiber made this phase interruptible by turning the recursive tree walk into an iterative loop with explicit yield points. startTransition marks work as low-priority so the scheduler can yield to higher-priority updates mid-traversal.

The commit phase — where React mutates the DOM — has never been interruptible and never will be. Once React starts committing, it runs to completion. This is not a limitation. It's a correctness guarantee. Understanding this boundary is the difference between reaching for concurrent features appropriately and being surprised when they don't solve your problem.

"Concurrent mode doesn't make React faster. It makes React smarter about which work to do first."

— Issue 14, p. 17

The remaining 18 pages cover exactly how the scheduler prioritizes work, what happens when you nest transitions, and a complete annotated walkthrough of the reconcileChildFibers source.

Read the Full Issue →
94%

of subscribers say Frontmatter changed how they approach architecture decisions

Subscriber survey · December 2025 · 1,204 respondents

Chapter 04 · Excerpt
"The flame chart is a post-hoc rationalization. You're looking at what happened, not at why it was allowed to happen."

Profiling Without Illusions

React DevTools Profiler shows you component render times. It does not show you why those components rendered, what caused the render to be scheduled, or whether the render was necessary. Three different questions with three different answers, and the tool answers none of them directly.

The useful signal is in the Interactions panel, which most engineers ignore. An interaction is a causal trace — it connects a user event to every render it triggered, across the entire component tree, including deferred work. This is where you find the renders you didn't know you were doing.

The second illusion is self-time. A component with 0.3ms self-time looks cheap in the profiler. But if it renders 847 times in a single interaction, the cumulative cost is 254ms — enough to miss the 16ms frame budget 15 consecutive times. Self-time without render count is meaningless.

The third illusion is the most dangerous: profiling under DevTools in development mode. React development builds include extra validation passes, double-invocation of render functions, and synchronous error boundary handling that doesn't exist in production. Your profiler numbers in dev are structurally different from production behavior, not just slower.

Measuring What Actually Matters
<span class="code-token-comment">// Trace renders with causality, not just duration</span>
<span class="code-token-keyword">import</span> { unstable_trace <span class="code-token-keyword">as</span> trace } <span class="code-token-keyword">from</span> <span class="code-token-string">'scheduler/tracing'</span>;

<span class="code-token-keyword">function</span> <span class="code-token-fn">handleSearch</span>(query: <span class="code-token-type">string</span>) {
  <span class="code-token-fn">trace</span>(<span class="code-token-string">'search-input'</span>, performance.<span class="code-token-fn">now</span>(), () => {
    <span class="code-token-fn">setSearchQuery</span>(query);
    <span class="code-token-fn">setPage</span>(<span class="code-token-num">1</span>);
    <span class="code-token-fn">clearFilters</span>();
  });
  <span class="code-token-comment">// Now DevTools Interactions shows every render</span>
  <span class="code-token-comment">// caused by this single user action — across</span>
  <span class="code-token-comment">// all three state updates, batched or not</span>
}

<span class="code-token-comment">// Production-accurate profiling via web-vitals</span>
<span class="code-token-keyword">import</span> { onINP } <span class="code-token-keyword">from</span> <span class="code-token-string">'web-vitals'</span>;

<span class="code-token-fn">onINP</span>(({ value, attribution }) => {
  <span class="code-token-comment">// attribution.eventTarget tells you exactly</span>
  <span class="code-token-comment">// which element triggered the slow interaction</span>
  console.<span class="code-token-fn">log</span>(<span class="code-token-string">`INP: ${value}ms on ${attribution.eventTarget}`</span>);
});
Past Issues

Browse the Archive

View all 14 issues →
13
Jan 2026

Partial Hydration

Islands architecture, selective hydration, and the cost of JavaScript

2,847 readers
12
Dec 2025

State Machines in Production

XState, actor model, and why your useState spaghetti is a finite state machine in denial

3,104 readers
11
Nov 2025

The Module Bundler

Rollup, esbuild, Vite — what they actually do and why it matters for your DX

2,619 readers
10
Oct 2025

TypeScript at Scale

Compiler performance, declaration files, and the project references you're not using

3,891 readers

Not ready to subscribe? Read a full issue free — Issue 12 on state machines is publicly available.

Issue 14 · February 2026

Read the
Full Issue.

32 pages. One concept. No padding. Delivered the first Thursday of every month to engineers who want to understand their tools all the way down.

One email per month. No tracking pixels. Unsubscribe in one click.

Not sure yet? Browse the archive — Issue 12 is free to read in full.