All posts
Engineering

Source Maps and Symbolication, Explained From First Principles

Minified stack traces are useless. Here is what actually happens between a browser stack trace and a readable one: VLQ mappings, debug IDs, and why symbolication is a cache problem.

What a stack trace becomes after bundling

Your users' browsers never see src/app/checkout.tsx. They see app.4f8c21a9.js line 1 column 88412. Every error-reporting tool therefore needs a translation layer, and that layer is the source map: a JSON file whose mappings field encodes generated-position -> original-position pairs using base64 VLQ deltas.

From mappings to readable frames

Symbolication takes each (line, column) pair from the minified stack, finds the enclosing mapping segment, and rewrites the frame. Sounds trivial until you have 400MB of maps and a p99 SLA.

TODO-content: TODO-content: cover in order: 1. the VLQ encoding with a tiny worked example (encode one segment by hand) 2. why we store source maps out-of-band at upload time (sourcemap-upload docs page) instead of shipping sourceMappingURL comments to prod 3. debug IDs: what problem they solve when artifact hashes collide across deploys (link js-sdk/debug-ids docs) 4. the symbolicator service architecture: parse-once + mmap + LRU cache, link the system-design-of-a-symbolicator post 5. the same story for Dart/Android/iOS: dwarf/proguard/dSYM and how /symbolicator handles each Finish with a checklist: upload maps in CI, keep release names stable, verify with the symbolicator playground.

Subscribe

Get new engineering posts in your inbox