#performance
49 posts

Astro 7.4.2 turns a 60-second content sync into under a second by counting bytes differently
On a 44k-entry store, the chunking step drops from about 60 seconds to well under one second with byte-identical output. The fix is not a faster algorithm, but a different way to know how wide a character is.

Bun 1.4.4 ships a formatter: 59 milliseconds on Prettier's own repo, 286x faster
bun fmt reads your existing Prettier config and plugins, running 59.7 ms against 17.1 s on Prettier's own repository, 48 MB against 459 MB. What matters is how it proves identical output: byte comparison plus a semantic re-parse check.

Electron 45 lands Chromium 156, Node 24.22 and V8 15.6 — and every breaking change sits on a sandbox boundary
Three breaking changes: sandboxed preload scripts lose events/timers/url and the Buffer globals, Workers created inside iframes no longer inherit Node integration, and extension pages stop receiving preload scripts unconditionally.

llama.cpp build 11899: giving multimodal clients an interface to ask what a model supports
b11899 is a nightly build whose only substantive change adds mtmd_helper_get_capabilities, reporting audio_stream, speaker reference and text generation while keeping the old API. The build number itself tells you how this project ships.

Ruff 0.17.2 adds a preview rule against repeated regex compilation, plus a batch of false-positive fixes
Mostly false positives: starred type variable constraints, backslash-escaped args in pydocstyle, star elements in pylint. It also marks comment-deleting fixes unsafe and lands two performance changes.

TypeScript 7.1 Beta: ambient modules can finally declare import attributes, and --target reaches es2026
The beta has six sections: import attributes in ambient modules, source phase imports, --target es2026, new library methods, the 7.1 API (snapshots, file system, content mappers) and a few behavioral changes.

Half of Vite 8.3.5's fixes live in bundled-dev: bundling during dev is still catching up
Eight of 21 fixes carry the bundled-dev prefix — HMR propagation, error stack mapping, server.origin, import.meta.env injection — plus two chunk import map correctness fixes and a CSS percent-sign build failure.

Vue 3.6's 13th release candidate: seven of eight fixes live in the Vapor compiler
Almost everything in 3.6.0-rc.13 points at compiler-vapor, plus one change that restores the 200ms default delay for async components. The first says Vapor is still catching up on semantics; the second says defaults are API.

Python 3.15 lands: UTF-8 by default, frozendict built in, a slightly faster JIT
Python 3.15.0 shipped on October 9 with 5,643 commits from 1,012 contributors. What UTF-8 defaults, lazy imports, frozendict and the JIT change for you.

Safari TP 254 brings calc-size(), size shorthands and live pinch-to-zoom
Safari Technology Preview 254 adds calc-size(), size and per-side radius shorthands, plus live pinch-to-zoom on macOS. What changes in your CSS.

Servo 0.6 turns CSS Grid on by default, and a lot of sites finally line up
Servo 0.6.0 ships August's 417 commits and turns CSS Grid on by default. What in the release notes actually changes how pages render.

Zig 0.17: the grammar starts to freeze and the build system splits in two
Zig 0.17.0 shipped on October 2 after five months, 206 contributors and 925 commits: syntax breaks, stdlib renames and the build-system split.

Three hours of Cloudflare 5xx: how one config change took down half the web
On November 18, 2025, Cloudflare's core proxy returned 5xx for about three hours and a large share of the web went down with it. The postmortem points at an internal configuration change, not an attack — and the blast radius is the lesson.

Ten open-source games, 48 MB: what self-hosting third-party games actually costs
I vendored ten MIT/public-domain HTML5 games into this static site — 48.4 MB in total. The work was not copying files; it was licences, size, and the fact that all of them loaded things from CDNs.

When a 3D scene should actually start loading
Fourteen Three.js scenes on one site is not a rendering problem, it is a scheduling problem. Two gates, one SPA navigation bug, and the WebGL context I forgot to release.

Reading DeepSeek official charts: what V4.1 Flash-1017 actually improves
I pulled the benchmark table, the performance-cost chart and the case images from DeepSeek's official changelog. The update is about doing work, not about being smarter — and the price did not change.

Search on a bilingual static site: the Pagefind trade-offs
A static site has no backend, so search has to be baked in at build time. Pagefind fits, even though it does not stem Chinese and prints a warning every build — neither is a bug.

How a CDN puts your content next door
A site hosted in Virginia can serve you images from a machine in your own city. This covers the three jobs of a CDN, why cache hit ratio is the only metric that really matters, what else edge nodes do, and why CDNs fight to get into internet exchanges.

HTTP/3 and QUIC: routing around TCP
HTTP/3 is the first HTTP that does not run on TCP. This covers where TCP head-of-line blocking actually hurts, what QUIC moved into user space, how connection migration works, and what the switch costs.

Cooling Data Centers: From Blowing Air to Taking a Bath
AI racks have outgrown air cooling. Here is why data centers are switching cooling methods, and what air, direct-to-chip liquid and immersion cooling each cost.
Upgrading to Astro 7: the Rust compiler is fast, the cold cache is what bit me
Astro 7 moved the compiler and the Markdown pipeline to Rust and switched the bundler to Rolldown. The upgrade was quick; the failures it surfaced afterwards were not.
PostgreSQL 19: REPACK, WAIT, and a planner you can finally argue with
PostgreSQL 19 merges VACUUM FULL and CLUSTER into REPACK, adds a WAIT command for catching a standby up, and ships two extensions that pin planner decisions. The features I actually care about, plus three incompatibilities that bite.
Chrome 155: JPEG XL is back, and post-quantum lands in Web Crypto
Chrome 155 decodes JPEG XL directly through jxl-rs, a Rust decoder, and adds ML-KEM and ML-DSA to the Web Crypto API.
Wikipedia names rogue agents: after millions of requests
The Wikimedia Foundation publicly accused unauthorised OpenAI agents of millions of requests, questionable edits and tool tampering, possibly worsening a rare service disruption.
Putting a Three.js island inside a static site
The isle page downloads only its own script. The scene is computed at runtime, Three.js stays in that page's chunk, and the first HTML response carries an empty stage.
Twelve hundred instances: squeezing a garden into a few draw calls
Six hundred blades of grass, a hundred and twenty flowers, eighty-five mossy stones, forty-two shrubs. Density comes from InstancedMesh, not from cutting the count.
The loading budget for 3D: split the chunk, load on visibility, know when to stop
A 3D page pays three costs — download, first-frame compilation, per-frame drawing. Each needs its own budget, and any one of them can turn good-looking into janky.
<template for>: letting HTML declare which region gets replaced
Chrome 150 supports the template for attribute: processing instructions mark replaceable regions, and streamed templates fill them. How it works, what it solves, and why it should not go anywhere near production yet.
Misusing big O: constants and preconditions decide more than the order
An O(n log n) sort can lose to O(n²) insertion sort, and an O(1) hash lookup can lose to an array scan. Check input size, constants and memory locality before judging speed.
Debounce vs throttle: the difference is who decides when to run
Both limit how often a function runs. Debounce lets the last call decide the moment; throttle uses a fixed window. The wrong pick shows up as a laggy drag or a request every 200ms.
The game loop: why delta time is not optional
Moving 5 pixels per frame runs twice as fast on a 60Hz screen and two and a half times as fast at 144Hz. Multiply by elapsed time to decouple physics from refresh rate, then cap it.
HTTP caching: Cache-Control and ETag each own half
Cache-Control decides whether a request happens; ETag decides whether the response body can be skipped. Mixing them is why cache bugs persist: changing one never fixes the other half.
Memory layout: the same algorithm, ten times slower, is usually cache
A trip to main memory costs hundreds of cycles; a cache line fetch costs one. Sequential versus random access often outweighs the algorithmic order itself.
The N+1 query: the most typical ORM performance trap
Fetch 100 rows and query the relation for each one and you have made 101 queries. There are only three fixes: eager load, batch fetch, or use a single join.
Rate limiting: what token bucket and leaky bucket really differ on
A token bucket permits bursts; a leaky bucket flattens traffic to a constant rate. Picking wrong shows up as throttled normal users, or a limit that does nothing.
Sliding windows: decide what the window tracks before writing the loop
A window works when validity changes monotonically with its edges. Write down the tracked state and the shrink condition first, and the two-pointer loop amortises to O(n) on its own.
Monotonic stacks: next greater element in O(n), not O(n squared)
Each index is pushed and popped at most once, so what looks like a nested loop is linear. Recognise the first larger or smaller neighbour shape and the same template applies.
Counting the ones in a binary number: from loops to SWAR
Popcount has three forms: loop once per set bit, a lookup table, or SWAR across bit fields. They differ by orders of magnitude, and Rust and WebAssembly already expose it as a single instruction.
Union-find: two lines of optimisation make every operation near constant
Path compression flattens the tree, union by size stops it growing tall. You need both before the cost drops to the inverse Ackermann function, which is never above 5 in practice.
Islands are not Web Components: two different kinds of on-demand loading
Islands decide at build time where JavaScript is needed and when it hydrates. Web Components give the browser a self-contained element at runtime. Confusing them picks the wrong tool.
Cache headers for a static site: hashed files forever, HTML never
A cache policy depends on whether the filename changes with the content, not on file size. Long-caching HTML hands users an old entry point that points at deleted chunks.
When WebAssembly earns its place: less often than the pitch suggests
WASM pays off with heavy computation, bulk data and few boundary crossings. Rewriting an O(n) JavaScript loop as WASM usually buys slower loading and a harder stack to debug.
Stop guessing the header height: measure it with ResizeObserver
A wrapping navigation, late webfonts and changing content all break constants written into CSS. A ResizeObserver watches the element and writes the measured value back into a variable.
Full-text search on a static site: index at build time, no backend at runtime
A static site does not need Algolia to have search. Generate the index during the build, run the query entirely in the browser, and pay a few seconds of build time.
Pushing first-load JS to zero with Astro islands
From "async import" to "hydrate on demand" — what each of the three lazy-loading layers actually solves, with the code that runs on this site.
One source for head: SiteHead, JSON-LD escaping and hreflang
All three HTML shells render one component that emits every head tag, with the data assembled on the server. Plus a detail worth remembering: angle brackets in JSON-LD must be escaped.
Shipping a static site is not "upload the folder": caching, compression, honest 404s
Almost every static-hosting bug lives in response headers. Which files may be cached forever, which may not be cached at all, and why a static site must never use an SPA fallback.
Pagination at build time: why a static site should not page with a query string
The post list is sliced into static pages during the build, so page N is a real route. No client-side paging logic, no query string, just links.
No client:only for app pages: a static shell plus an explicit mount
Game and tool pages are a shell plus createApp, not client:only. I own the loading, ready and error states, and the retry button actually works.
