TL;DR
Lightpanda replaced LibDOM with a custom Zig-based DOM (zigdom) after a six-month prototype to remove integration friction between V8, the Zig layer, and LibDOM. The project also adopted servo's html5ever for parsing and used V8 snapshots to reduce startup time; memory and CPU improved by single-digit percentages, with the primary gain being a more cohesive, extensible codebase.
What happened
Lightpanda removed LibDOM and implemented a new DOM written in Zig, called zigdom. The change grew from a six-month spare-time prototype that explored architecture and even briefly used QuickJS-NG; by mid-November the team began integrating the Zig implementation alongside V8. The new design represents nodes with a linked list of children and an optional parent pointer, a tagged union _type that stores node variants as pointers, and an _proto field for event-target behavior. To reduce allocation overhead the implementation bundles multiple object layers into a single allocation and uses lazy, per-page storage for rarely accessed element properties (classes, styles, dataset, relLists), saving several pointers per element. For HTML parsing the project uses servo's html5ever via a C binding. The team also generated V8 snapshots to speed startup — produced at runtime in debug and embedded at compile-time in release builds. Small performance and memory gains were reported, but the major advantage is tighter control over events, Custom Elements, ShadowDOM and future enhancements. zigdom has been merged into Lightpanda's main branch.
Why it matters
- A single Zig-based DOM removes the friction of bridging V8, Zig glue code, and a separate LibDOM implementation.
- Tighter control over memory layout and allocation makes future changes (events, Custom Elements, ShadowDOM, and other features) easier to implement.
- V8 snapshots and a leaner DOM reduce startup time and produce small CPU and memory improvements.
- A unified codebase in Zig simplifies extensions and could ease later architectural work such as concurrency or threading changes.
Key facts
- LibDOM was replaced by a Zig implementation named zigdom after about six months of prototyping.
- zigdom represents nodes with a linked list of children, an optional parent pointer, a tagged union _type, and an _proto EventTarget pointer.
- To lower allocation overhead, zigdom performs a single large allocation that covers multiple object layers instead of several small allocations.
- Element properties like classes, styles, relLists and dataset are stored lazily via a per-page element->property lookup, removing roughly six pointers per element.
- HTML parsing is handled by servo's html5ever (Rust) with a C binding; the integration was described as straightforward.
- V8 snapshots were used to preinitialize environment state: generated at startup in debug builds and embedded into release binaries at compile-time.
- Measured CPU and memory improvements are in the single-digit percent range; the main benefit cited is codebase cohesion and extensibility.
- Work on zigdom began as a spare-time prototype and zigdom has since been merged into Lightpanda's main branch.
- An AI coding agent (Claude) assisted in the project; the author found the experience positive overall but noted tooling and review UX limitations.
What to watch next
- Further improvements and feature work around Custom Elements and ShadowRoot enabled by the unified Zig codebase.
- Expanded use of Zig across other parts of Lightpanda and how that affects future architecture and tooling.
- not confirmed in the source: a public roadmap or timeline for additional performance benchmarks and multi-threading support.
- not confirmed in the source: adoption plans for zigdom outside Lightpanda or wider community contributions.
Quick glossary
- DOM: Document Object Model; a programmatic representation of a document (such as HTML) that scripts can inspect and modify.
- V8 snapshot: A serialized, preinitialized V8 heap image used to speed up the creation of V8 execution environments by avoiding repeated setup work.
- Shadow DOM: A web platform feature that lets components encapsulate DOM subtrees and styles so they don't collide with the main document.
- Custom Elements: A web platform API that allows developers to define new HTML tags with custom behavior implemented in JavaScript or the embedding environment.
- html5ever: An HTML parser written in Rust, designed for correctness and used in projects such as the Servo browser engine.
Reader FAQ
Why did Lightpanda replace LibDOM?
They encountered integration friction between V8, the Zig layer, and LibDOM—particularly around events, Custom Elements, ShadowDOM and memory cohesion.
Did this change improve performance?
Yes; the team reports single-digit percentage improvements in CPU and memory, though the primary benefit cited is a more cohesive codebase.
What HTML parser does Lightpanda use now?
They use servo's html5ever with a C binding to integrate it.
Was V8 replaced in production?
The prototype briefly experimented with QuickJS-NG, but integration proceeded with V8; zigdom was integrated alongside V8.
Is the zigdom source available publicly?
The post points readers to the project's GitHub to inspect the Node, Element, and event system source code.

CTRL K Back Migrating our DOM to Zig Karl Seguin Software Engineer zig architecture dom performance v8 Thursday, January 8, 2026 TL;DR We replaced LibDOM with our own Zig-based DOM…
Sources
- Lightpanda migrate DOM implementation to Zig
- Lightpanda browser now uses libcurl – Blog
- Lightpanda: the headless browser designed for AI and …
- Why We Built Lightpanda in Zig – Blog
Related posts
- Microsoft schedules a heavy slate of product retirements across 2026
- Voice Composer: Browser-based Pitch Detection Converting Voice to MIDI
- Code Is Cheap Today; Building Durable Software Still Demands Engineers