Skip to content
X Web Rewrite: Vite + Node 26 Achieve 8x Faster First Paint

X Web Rewrite: Vite + Node 26 Achieve 8x Faster First Paint

X (formerly Twitter) rewrote its web application using Vite, Node.js 26, and Fastify, replacing a fragmented architecture with a unified streaming SSR system that delivers first tweets in 1.7 seconds on slow 4G, cutting JavaScript download to zero before first paint.

Node.js Tech Stack
Node.js Tech Stack
Node.js Tech Stack

On November 6, Evan You (尤雨溪) shared a post celebrating that X's web client now runs on Vite. The rewrite, led by X chief engineer and Node.js core contributor Yagiz Nizipli, was detailed in an official engineering blog post on November 4. A core team of fewer than five engineers, aided by AI coding tools, replaced the legacy architecture in under six months. In weak‑network conditions the new version shows the first tweet in 2.7 seconds versus over 22 seconds for the old version — an 8× improvement.

Legacy architecture and its problems

The old codebase, codenamed rweb, originated from Twitter Lite (2017). It served an empty HTML application shell and relied on client‑side JavaScript to fetch data. To satisfy search‑engine indexing, two separate server‑side rendering systems — rweb SSR and Jetfuel SSR — were bolted on. This resulted in three independent services; changing an SEO field or a 404 status code required edits in three codebases. Worse, bots received fully rendered HTML while unauthenticated human users got only the empty shell. On the old rweb a browser had to complete four serial network round‑trips: download the shell, download and execute several megabytes of JS, resolve the username to an account ID, then fetch the tweet list. Each round‑trip added latency, leaving users staring at a spinner. The stack also mixed Redux, Relay, Flow, and Webpack, making changes increasingly painful.

Architecture comparison before and after rewrite: three independent services merged into a single application
Architecture comparison before and after rewrite: three independent services merged into a single application
Old rweb 4 serial network round‑trips vs new single streaming HTML response
Old rweb 4 serial network round‑trips vs new single streaming HTML response

Unified stack: Vite, Rolldown, Fastify, and Node.js 26

The team considered merely swapping the toolchain or adopting Next.js but concluded that a full rewrite was cleaner. The new build pipeline uses Vite and the Rust‑based bundler Rolldown; linting is handled by Oxlint; TypeScript type checking runs on the Rust compiler tsrs. On the server, Express was replaced by Fastify running on Node.js v26, with Platformatic Watt managing multiple worker threads in a single process — threads that stall or exceed memory limits are automatically replaced. The UI layer is a new XDS component library built on Base UI and Tailwind CSS.

Differentiated request handling

A single request is routed based on visitor identity:

Human users receive React streaming SSR: the page shell is sent first, then each module's HTML streams as its data resolves. GraphQL responses are embedded in the page so the browser can replay them without re‑fetching.

Search‑engine crawlers are identified by verifying their real IP address at the edge (not the easily spoofed User‑Agent). They receive a complete static HTML document after all modules finish rendering, with all client‑side JavaScript stripped out.

Link‑preview bots (iMessage, Slack, etc.) skip body rendering entirely and receive only <head> tags and card images generated by a Rust‑rewritten image service.

AI‑assisted development with guardrails

With fewer than five engineers, the bulk of mechanical work — porting legacy service logic, writing pages, generating tests — was delegated to AI agents. Humans focused on architecture, code review, and real‑browser validation. Two key safety nets kept the agents in check:

The two legacy SSR services served as living reference implementations. A script impersonated Googlebot to hit both old and new endpoints simultaneously, automatically comparing status codes, titles, and structured data. Agents mimicked the old logic and wrote tests; engineers only had to watch the diff shrink to zero.

The repository enforces three layers of discipline:

A root AGENTS.md file codifies coding standards.

Over 20 high‑frequency development actions are packaged as version‑controlled Skills.

An Oxlint plugin named anti‑slop blocks common AI‑generated anti‑patterns at pre‑commit: chained type assertions, indiscriminate unknown parameter types, and conditional spreads on empty objects.

In early September all crawler traffic was switched to the new service; Jetfuel SSR and rweb SSR were shut down and roughly 36,000 lines of legacy code were deleted.

Performance optimizations and real‑world results

From September onward the team merged 80+ performance‑focused commits. Two notable examples:

Rolldown's default code‑splitting had produced 582 tiny chunks for the unauthenticated entry point. Limited to ~100 concurrent streams per connection, this required eight round‑trips just to fetch the startup files. A custom build plugin consolidated them into 10 chunks.

An inline script was added to delay JavaScript injection until the CSS stylesheet finishes loading, preventing scripts from contending for bandwidth on slow networks. This alone cut the first‑paint time on the unauthenticated tweet page from 7.2 seconds to 1.8 seconds.

Median time to first tweet comparison between old and new versions under Slow 4G + 4× CPU throttling
Median time to first tweet comparison between old and new versions under Slow 4G + 4× CPU throttling

Under simulated Slow 4G with 4× CPU throttling on November 3:

Old rweb: 22–25 seconds to show the first tweet.

New version: 1.7 seconds for a single tweet ( @SpaceX, 12.8× faster); 3.0 seconds for a profile page (8.2× faster).

Compressed JavaScript bytes downloaded before first tweet appears: old version 3.0–3.6 MB, new version 0 KB
Compressed JavaScript bytes downloaded before first tweet appears: old version 3.0–3.6 MB, new version 0 KB

Perhaps the most striking metric: before the first tweet appears, the old version downloaded 3.0–3.6 MB of compressed JavaScript regardless of page; the new version downloads 0 KB because the content is already embedded in the initial HTML payload.

Current rollout status

As of the article's publication, all unauthenticated x.com traffic and all crawler traffic run on the new service. Unauthenticated server instances per data center have been halved from 1,400 to 700. The logged‑in Home timeline remains client‑side rendered for now; the team is gradually migrating logged‑in users by country. Once the global rollout completes, the decade‑old codebase will be fully retired.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performance optimizationViteReact SSRstreaming SSRFastifyRolldownX (Twitter)Node.js 26
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.