Tags: web-dev concept

Source Maps

Date: 2026-08-17


A mapping from generated code back to the source that produced it, so a stack trace names your file and line rather than app.a3f9c.js:1:48201. The only real decision is whether to expose them publicly, and it’s a smaller security question than it’s usually treated as.


A source map is a JSON file relating positions in generated output to positions in original source, letting debuggers and error reporters show the code you wrote.

What it contains

{
  "version": 3,
  "sources": ["src/basket.ts", "src/price.ts"],
  "sourcesContent": ["export function ...", "..."],
  "names": ["calculateTotal", "items"],
  "mappings": "AAAA,SAASA,eAAeC..."
}
  • mappings — the position data, in a compact encoding
  • sourcesContent — the complete original source, embedded. This is the part with the privacy implication
  • names — original identifiers, so minified t becomes total again

Without one

TypeError: Cannot read properties of undefined
    at t (app.a3f9c2e1.js:1:48201)

Effectively undebuggable. With a map:

TypeError: Cannot read properties of undefined
    at calculateTotal (src/basket.ts:42:18)

This is the entire value, and it applies to production error reporting far more than to local debugging — locally you have the source anyway.

The modes

source-map          separate .map file,
                    referenced in a comment
                    → browsers fetch it when
                      DevTools is open

hidden-source-map   generated, but NO
                    reference comment
                    → upload to your error
                      reporter; the public
                      never fetches it

inline-source-map   base64'd into the file
                    → huge. Development only

eval-source-map     fastest rebuilds
                    → development only

false               none

hidden is the right production answer for most teams. You get readable stack traces in your error reporter, and the map isn’t served publicly.

The exposure question, honestly

A public source map reveals your source code. How much that matters depends on what’s in it:

  • Client-side JavaScript is already public. Minified code is inconvenient to read, not secret. Anyone motivated can un-minify it
  • What a map genuinely adds is comments, original variable names, file structure and dead code paths — which is convenience for a reader, not new capability
  • The real risk is what shouldn’t be in client code at all — a hard-coded key, an internal endpoint, a comment describing an unreleased feature. Those are the actual problem, and the map just makes them easier to find — Secrets Management

So the honest position: hidden maps are the sensible default, and if a public map would expose something dangerous, you have a bigger problem than the map.

Uploading to an error reporter

# generate without a public reference
vite build   # sourcemap: 'hidden'
 
# upload, then delete before deploying
sentry-cli sourcemaps upload ./dist
rm ./dist/**/*.map

The release identifier must match between the uploaded map and the deployed code, or the reporter can’t pair them — and a mismatched release is the usual reason “we uploaded source maps and traces are still minified”.

Where they break

  • Not uploaded on deploy. Silently minified traces for weeks before anyone notices
  • Stale maps from a previous release, producing confidently wrong line numbers — worse than none
  • Chained transformations — TypeScript → transpiler → bundler → minifier, where any step not forwarding the incoming map loses the chain and points at intermediate code
  • Third-party scripts have no maps, so their errors stay opaque — one reason a global error handler is full of unattributable noise — Third-Party Scripts
  • Served with the wrong content type, or blocked by a CDN rule matching .map

CSS too

Often forgotten, and useful for the same reason:

generated  .css-1x2y3z { padding: 8px }
mapped     src/Button.module.scss:14

Worth enabling in development, where “which file produced this rule” is a real question in any component-scoped CSS setup.

The practical setup

DEVELOPMENT   full source maps, fastest
              variant

PRODUCTION    hidden-source-map
              → upload to the error reporter
              → delete before deploying
              → verify the release ID matches

And check it works. Throw a deliberate error in a staging deploy and confirm the trace is readable — this is a thing that silently stops working and is only discovered during an incident.