TL;DR
A source map is a JSON file that links minified production JavaScript back to the original source files. For any line and column in the built bundle, it records which source file, line, column and name it came from. Developer tools and error trackers use it to turn an unreadable stack trace back into your own code.
In this guide
What's inside a source map?
Here's a three-line function built with esbuild, minified, with source maps turned on.
export function formatTotal(order) { return order.totals.grand.toFixed(2);}
The build writes two files. The bundle has the code squeezed onto one line, with a comment at the end:
function o(t){return t.totals.grand.toFixed(2)}export{o as formatTotal};//# sourceMappingURL=cart.js.map
And cart.js.map next to it holds this:
{ "version": 3, "sources": ["../src/cart.js"], "sourcesContent": ["export function formatTotal(order) {\n return order.totals.grand.toFixed(2);\n}\n"], "mappings": "AAAO,SAASA,EAAYC,EAAO,CACjC,OAAOA,EAAM,OAAO,MAAM,QAAQ,CAAC,CACrC", "names": ["formatTotal", "order"]}
sources lists the original files. names holds the identifiers the minifier renamed, which is how o becomes formatTotal again. mappings is the actual map: each comma-separated chunk is a run of Base64 numbers saying "this column in the output came from that file, line, column and name". You'll never read it by hand.
sourcesContent is the one to notice. It's optional, and it embeds your original source code, comments included, inside the map. Whether you publish that field is most of the decision later on this page.
How does a browser find the source map?
A browser or tool finds a source map in one of three ways: a sourceMappingURL comment at the end of the JavaScript file, a SourceMap HTTP header on the response that served the file, or a map inlined as a base64 data URL in that same comment. A relative URL resolves against the JavaScript file's own address.
| Method | What it looks like | Good for |
|---|---|---|
| Comment | //# sourceMappingURL=cart.js.map on the last line | The default in almost every bundler |
| HTTP header | SourceMap: /assets/cart.js.map | Adding maps without rebuilding the files |
| Inline | //# sourceMappingURL=data:application/json;base64,eyJ2… | Local development only |
CSS uses the same idea with a /*# sourceMappingURL=… */ comment. The older X-SourceMap header still works in most tools, but SourceMap is the current name.
Inline maps belong in development. They put the whole map inside the bundle, so every visitor downloads it, and a map is usually bigger than the code it describes. A separate .map file costs your visitors nothing, because browsers only fetch it when someone opens the developer tools.
Should you ship source maps to production?
For most web apps, yes. Your JavaScript is already public, because every visitor downloads it, and minification shrinks files rather than protecting anything. A public source map gives away your original names, file layout and comments. It doesn't give away anything a determined person couldn't already work out from the bundle, and it makes every production error readable.
That's my view, and there are honest reasons to disagree. If the comments say things you wouldn't put in a public repo, if the client-side code is genuinely what customers pay for, or if file names announce features you haven't launched, publishing sourcesContent hands all of that over neatly formatted. Note what isn't on that list: secrets. An API key in a source map was already in the bundle, and the map isn't the problem.
| Approach | Who can read your source | Readable traces in developer tools | Works with tools that fetch maps |
|---|---|---|---|
| Public maps | Anyone who looks | Yes, for everyone | Yes |
| Hidden maps, uploaded to an error tracker | Only that tracker | No | No |
| No maps | Nobody | No | No |
Hidden maps are the usual middle ground: the bundler writes the .map files but leaves out the comment, and you upload the maps to your error tracker and keep them off the public site. That works if one tool is all you need. It also means anything else that reads maps from your site, Rebase included, finds nothing, and your own developer tools show minified code in production unless you load a map by hand.
There's a half step too. A map without sourcesContent still turns o back into formatTotal at src/cart.js:2, but doesn't publish the code itself. You can open the file locally.
How to turn source maps on
Every major build tool has a setting for public maps, and most have a hidden variant.
| Tool | Public maps | Hidden maps |
|---|---|---|
| Vite | build.sourcemap: true | build.sourcemap: 'hidden' |
| webpack | devtool: 'source-map' | devtool: 'hidden-source-map' |
| Rollup | output.sourcemap: true | output.sourcemap: 'hidden' |
| esbuild | --sourcemap | --sourcemap=external |
| Next.js | productionBrowserSourceMaps: true | No built-in option |
How to check your source maps work
Open your site, find the main bundle in the Network panel, and check its last line for the comment. Then request the map yourself:
curl -sI https://shop.example.com/assets/index-B7c2x9Qe.js.map
You want a 200 and a JSON content type. The usual failures are boring. The deploy step skipped .map files, a CDN rule blocked them, or the map on the server came from a different build than the bundle it sits next to, so every line points somewhere slightly wrong. That last one is the nastiest, because nothing errors. Build the bundle and its map in the same step, and deploy them together.
For support teams
If engineering says an error report is "minified and useless", it usually means the source maps aren't reachable from the place that's reading them. That's a build setting, not a missing piece of the report, and it's worth raising once rather than living with.
More on Console and dev tools