The basics
What is a source map file?
The JavaScript and CSS that websites send to browsers is rarely the code developers wrote. It has been compiled from TypeScript or JSX, merged from dozens of files into one bundle, and minified, with names shortened and all spacing removed. That's good for speed and bad for debugging: an error at line 1, column 2,817 of app.min.js tells you nothing. A source map records where every piece of the output came from, so browser developer tools can show the original files, with their names, comments and line numbers, while the optimised code runs.
Source maps are generated by build tools, never written by hand. They're named after the file they describe plus .map (app.min.js gets app.min.js.map, styles.css gets styles.css.map), and nothing loads them in normal use: browsers only fetch them when developer tools are open.
Other .map files
The .map extension is also used by unrelated formats, such as the linker map files C and C++ toolchains write, and level files for some game editors. If a .map file doesn't start with {, it isn't a source map.
Anatomy
What's inside a source map
A source map is one JSON object. This is the complete map from our sample-greet.min.js.map sample (formatted for reading), made by terser when it minified an 8-line file, greet.js, into one line: function greet(e){const o="Hello, "+e+"!";return console.log(o),o}greet("Ada");
{
"version": 3,
"file": "sample-greet.min.js",
"names": ["greet", "name", "message", "console", "log"],
"sources": ["greet.js"],
"mappings": "AAEA,SAASA,MAAMC,GACb,MAAMC,EAAU,UAAYD,EAAO,IAEnC,OADAE,QAAQC,IAAIF,GACLA,CACT,CACAF,MAAM",
"ignoreList": []
}- 1
"version": 3The version
Always the number 3. Versions 1 and 2 were early formats that nothing uses any more.
- 2
"file": "sample-greet.min.js"The generated file
Optional: the name of the file this map describes. Tools don't rely on it; the link from the code to the map matters more.
- 3
"names": [ … ]Original names
Identifiers from the original code. The minifier renamed
nametoeandmessagetoo; mappings point into this list so DevTools can show the real names. - 4
"sources": ["greet.js"]The original files
Required. Paths or URLs of the original files, relative to the map. A bundle's map lists every file that went into it.
- 5
"mappings": "…"The mappings
Required. The position data: for each piece of the generated code, which file, line and column it came from. It's encoded compactly, as explained below.
- 6
AAEAA segment
One mapping, four numbers in Base64 VLQ: generated column 0, source 0 (
greet.js), line 2, column 0. Lines and columns count from 0, so that's line 3 in an editor:function greet(name) {. - 7
SAASAA segment with a name
Five numbers: the fifth points into
names. This one mapsgreetin the minified code togreetin the original. - 8
, (commas) and ; (semicolons)Separators
Commas separate segments on the same generated line; a semicolon starts the next generated line. The minified code is a single line, so this map has no semicolons.
- 9
"ignoreList": []Code to skip
Indexes into
sourcesfor third-party code, such as libraries, that debuggers should hide or step over. Empty here. - 10
(no sourcesContent)Original code not included
This map has no
sourcesContent, so a debugger has to fetchgreet.jsfrom the server. Maps that include it work on their own, but publish your source code.
Linking
How a browser finds the source map
The generated file points to its map in one of two ways. A comment on its last line is the usual one; an HTTP header does the same without touching the file, and wins if both are present:
// last line of a JavaScript file
//# sourceMappingURL=sample-app.min.js.map
/* last line of a CSS file */
/*# sourceMappingURL=sample-styles.min.css.map */
# or an HTTP response header, which takes precedence
SourceMap: /js/sample-app.min.js.map- The URL is relative to the generated file, not to the page.
sample-app.min.js.mapmeans "next tosample-app.min.js". - It can be a
data:URL. The whole map, base64-encoded, then sits inside the comment. Oursample-inline.jswas made this way bytsc --inlineSourceMap --inlineSources: one file, nothing else to fetch, but much bigger. - Older syntax:
//@ sourceMappingURLand theX-SourceMapheader are deprecated. Tools should write//#andSourceMap, though browsers still accept the old forms. - No link at all is also an option. A "hidden" source map is generated but not referenced, and is uploaded to an error-tracking service or loaded by hand in DevTools instead.
The format
The fields of a source map
| Field | Required | What it holds |
|---|---|---|
version | Yes | The number 3 |
file | No | The name of the generated file |
sourceRoot | No | A prefix added to every entry in sources, for moving the originals to another folder or server |
sources | Yes | The original files, as relative paths or URLs; an entry can be null |
sourcesContent | No | The full text of each original file, in the same order as sources |
names | No | Original identifiers that mappings refer to |
mappings | Yes | The encoded positions |
ignoreList | No | Which sources are third-party code to hide when debugging. Some browsers also read the older x_google_ignoreList |
sections | Index maps only | A list of maps with offsets, used instead of sources and mappings |
Tools must ignore fields they don't recognise, which lets vendors add their own, usually with an x_ prefix. Additions are being worked on in TC39, the committee behind JavaScript: scopes (for showing original variable names and scopes while debugging), debug IDs (to match a map to its file without relying on URLs) and range mappings.
Under the hood
How the mappings string is encoded
mappings packs thousands of positions into a short string. It's built in three layers:
- 1Lines and segments. Each
;starts the next line of the generated file. Within a line,,separates segments, one per mapped piece of code. - 2Fields. A segment has 1, 4 or 5 numbers: the generated column; then the index into
sources, the original line and the original column (all counted from 0); then, optionally, an index intonames. - 3Relative values. Each number is stored as the difference from the same field in the previous segment, which keeps them small. Only the generated column resets at each new line.
- 4Base64 VLQ. Each number is written as Base64 characters carrying 6 bits each (
A=0 …Z=25,a=26 …z=51,0=52 …9=61,+=62,/=63). Of those 6 bits, the top one (32) means "more characters follow" and the other 5 carry data, lowest bits first. In the finished number, the lowest bit is the sign: odd means negative.
Here are segments from the greet.js map above, decoded. Line and column are shown counted from 1, as an editor shows them:
| Segment | Decoded | Minified column | Original position | Points at |
|---|---|---|---|---|
AAEA | 0, 0, +2, 0 | 1 | greet.js, line 3, column 1 | function |
SAASA | +9, 0, 0, +9, name 0 | 10 | line 3, column 10 | greet (name: greet) |
MAAMC | +6, 0, 0, +6, name +1 | 16 | line 3, column 16 | e, originally name |
GACb | +3, 0, +1, −13 | 19 | line 4, column 3 | const |
IAEnC | +4, 0, +2, −35 | 43 | line 6, column 3 | return: the minifier merged lines 5 and 6 into one statement |
OADAE | +7, 0, −1, 0, name +2 | 50 | line 5, column 3 | console |
CACAF | +1, 0, +1, 0, name −2 | 67 | line 8, column 1 | greet("Ada") |
Working through two characters: S is 18, binary 010010. The continuation bit (32) is off, so the number is complete; its lowest bit is 0, so it's positive; shifting off the sign bit leaves 9. In IAEnC, the fourth number is nC: n is 39, which has the continuation bit set, leaving 7; C is 2, worth 2 × 32 = 64 in the second position; 7 + 64 = 71, odd so negative, and 71 shifted right is 35: −35.
// greet.js: original source for sample-greet.min.js.map
// Free sample from 99helpers.com/file-types/map
function greet(name) {
const message = "Hello, " + name + "!";
console.log(message);
return message;
}
greet("Ada");function greet(e){const o="Hello, "+e+"!";return console.log(o),o}greet("Ada");
//# sourceMappingURL=sample-greet.min.js.mapVariants
Index maps: one map made of several
When files are simply joined together, re-encoding every mapping is wasteful. An index map instead lists the existing maps as sections, each with an offset: the line and column in the combined file where that part starts. Sections must be in order and must not overlap.
{
"version": 3,
"file": "sample-bundle.js",
"sections": [
{ "offset": { "line": 0, "column": 0 },
"map": { "version": 3, "sources": ["greet.js"], "mappings": "AAEA,…", … } },
{ "offset": { "line": 1, "column": 0 },
"map": { "version": 3, "sources": ["clock.js"], "mappings": "AAEA,…", … } }
]
}Index maps are part of the standard, but fewer tools write them than read them. Our sample-index.map combines the maps of two minified files and is a quick way to test whether a consumer supports sections.
How to
How to generate a source map
| Tool | Setting | Variants |
|---|---|---|
TypeScript (tsc) | "sourceMap": true | inlineSourceMap, and inlineSources to embed the originals |
| esbuild | --sourcemap | =inline, =external (no comment), =linked |
| Vite | build.sourcemap: true | 'inline', 'hidden' |
| webpack | devtool: "source-map" | hidden-source-map and many faster, less exact options |
| terser | --source-map "url=out.js.map" | content= to chain an earlier map |
When code passes through several tools, such as TypeScript then a bundler then a minifier, each step has to read the previous map and produce a combined one, or the final map points at an intermediate file. Most bundlers handle this for you. CSS tools, from Sass to PostCSS and esbuild, write .css.map files the same way; our sample-styles.min.css.map comes from esbuild minifying a stylesheet.
Debugging
How DevTools and Node.js use source maps
- Browser DevTools load the map when they open, then show the original files in the Sources (or Debugger) panel. Breakpoints, stepping and variable names work in the original code, and console messages link to original lines. In Chrome, the Developer resources panel shows whether each map loaded, and you can attach one by hand: right-click the file in Sources and choose "Add source map".
- Node.js maps stack traces back to the original files when started with
--enable-source-maps. Our samples show it: with the flag, an error thrown in minified code is reported atsample-app.tsline 23 instead of.min.jsline 1. - Error-tracking services receive minified stack traces from users' browsers and use uploaded source maps to turn them into readable ones, which is why hidden maps exist.
ignoreListlets DevTools hide library code from stack traces and skip it while stepping, so you only see your own files.
Security
The privacy risk of publishing source maps
A source map published next to your code can be downloaded by anyone, and it can reveal more than the minified code does:
sourcesContentis your source code, comments included: TODO notes, internal explanations, commented-out code, and occasionally keys or internal URLs that should never have been in front-end code at all.sourcesshows your project's layout: folder names, file names and sometimes absolute paths from the build machine, such as a username.namesrestores the identifiers that minification removed.
Minified code isn't secret either, so a source map rarely creates a new hole, but it makes reading your application much easier. Options, from most to least open:
- Publish maps with
sourcesContent(convenient; fine for open-source code). - Publish maps without
sourcesContent, so the original files have to be fetched separately and can be kept private. - Generate hidden maps, upload them to your error tracker, and don't deploy them. Check they really aren't deployed: a map without a comment is still found at the obvious URL,
app.min.js.map. - Keep maps on an internal server that only your team can reach, and load them in DevTools by hand.
Whatever you choose, never put secrets in front-end code. Anything a browser receives can be read, with or without a source map.
Troubleshooting
Why isn't my source map working?
| Symptom | Usual cause | Fix |
|---|---|---|
| "DevTools failed to load source map: Could not load content for …" | The map wasn't deployed, or the path in sourceMappingURL is wrong | Deploy the map, fix the path (it's relative to the JS file), or remove the comment |
| The map loads but fails to parse | The server answered the .map request with an HTML page, often a single-page app's fallback to index.html | Exclude .map from the fallback; serve it as application/json |
| Original files listed but empty | No sourcesContent, and the sources URLs aren't reachable | Include sourcesContent, or serve the originals where sources points |
| Breakpoints land a few lines off | The code was changed after the map was made, or one step in the build didn't pass its map on | Rebuild, and make sure every tool in the chain reads the previous map |
Paths like webpack:// or ../../src/ in the file tree | Not a problem: tools use their own prefixes or sourceRoot to group files | Nothing to fix |
Free downloads
Sample source map files to download
Free sample source maps for testing DevTools, error trackers, source map libraries and servers. Each was generated by a real tool from small original files, and decoded with the source-map library to check that a minified position maps back to the right original line and column.
Loading…What's inside sample-app.min.js.map
esbuild made this map when it bundled and minified two TypeScript files, sample-app.ts and format.ts, into sample-app.min.js (also below). Download both to the same folder and open the .js file through a page with DevTools open to see the originals.
version and sources
Version 3, and two original files, given relative to the map:
../src/format.tscomes first because the bundler placed its code first.sourcesContent
Both original files in full, including their comments: the numbered comments 1 to 3 in
sample-app.tsexplain what to look for, and its/*!comment survives into the minified file.mappings
434 characters with no
;, because the minified code is a single line. Decoding it maps thethrow new Errorin that line back to line 23 ofsample-app.ts.names
The original identifiers (
formatPrice,basket,total,items,checkout…) that esbuild shortened to single letters.What's missing
esbuild doesn't write a
filefield, and there's nosourceRootorignoreList: all optional. The link is the//# sourceMappingURL=sample-app.min.js.mapcomment at the end ofsample-app.min.js.
All sample Source map files
Bundled TypeScript (esbuild)
sample-app.min.js.map · 2.1 KB (2,177 bytes)
The map of two TypeScript files bundled and minified by esbuild, with
sourcesContentandnames. The original source carries numbered comments explaining what to look for.- Testing DevTools and source map libraries on a typical bundle
- Seeing what `sourcesContent` exposes
The minified file it describes
sample-app.min.js · 483 bytes
The one-line output that
sample-app.min.js.mapdescribes, ending with itssourceMappingURLcomment. Runs withnodeand printsTotal: €12.25.- Pairing with the map to test loading in DevTools
- Checking a server serves the `.map` next to the `.js`
Minimal map without sourcesContent (terser)
sample-greet.min.js.map · 235 bytes
The 235-byte map decoded segment by segment on this page, made by terser. It has
file,namesand an emptyignoreList, but nosourcesContent.- Learning and testing VLQ decoding by hand
- Testing consumers when originals must be fetched
JavaScript with an inline source map (tsc)
sample-inline.js · 1.7 KB (1,720 bytes)
Compiled by
tsc --inlineSourceMap --inlineSources: the map, with the original TypeScript inside it, is a base64data:URL in the last line. Runs withnode.- Testing `data:` URL source maps
- Showing how much an inline map adds to a file
Index map with two sections
sample-index.map · 1.1 KB (1,141 bytes)
Combines the maps of two minified files, at lines 1 and 2 of a joined bundle, using
sectionsandoffset. Decoded correctly by thesource-maplibrary.- Checking a consumer supports index maps
- Testing offset handling
CSS source map (esbuild)
sample-styles.min.css.map · 598 bytes
The map of a small stylesheet minified by esbuild, with
sourcesContent. The.badge:hoverrule in the one-line minified CSS maps back to line 15 of the original.- Testing CSS source maps in DevTools
- Comparing JS and CSS maps
Ways to test with them
- DevTools: put
sample-app.min.jsandsample-app.min.js.maponline together, load the script from a page, open DevTools, and look forsample-app.tsin the Sources panel. - Decoders: use
sample-greet.min.js.mapand the decoded table on this page as expected values for your own VLQ parser. - Index maps: feed
sample-index.mapto your tool. If it complains about a missingmappingsfield, it doesn't support sections. - Servers: request a
.mapfile from your site and check it comes back as JSON (application/json), not as an HTML fallback page. - Privacy checks: search your production build for
.mapfiles andsourcesContent, and compare with whatsample-app.min.js.mapreveals.
Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.
Put it online
Have a source map? Give it a link.
Drop a .map file on 99helpers and it gets its own address in seconds. Opening the link shows the JSON as plain text in the browser, and DevTools can load it from there with "Add source map".
Questions
Source map files, frequently asked
What is a .map file?
Usually a source map: a JSON file that links minified or compiled JavaScript or CSS to the original source, so developer tools can show the original. Other programs use .map for unrelated things, such as linker output and game levels.
What is a .js.map file?
The source map for the JavaScript file with the same name minus .map. Browsers only download it when developer tools are open.
Should I deploy source maps to production?
It depends on how much you mind people reading your code. Maps with sourcesContent publish your original source and comments. Many teams generate hidden maps and upload them only to their error tracker.
Do source maps slow down my website?
No. Normal visitors never download them; browsers only fetch them when developer tools are open. Inline maps are the exception: they make the JavaScript file itself much larger.
How do I open a source map?
It's JSON, so any text editor or browser shows it. To use it, open the code it belongs to with browser DevTools, or decode it with a library such as source-map.
What is sourceMappingURL?
A comment at the end of a JavaScript or CSS file, such as //# sourceMappingURL=app.min.js.map, that tells developer tools where the map is. The URL is relative to the file.
What do the letters in mappings mean?
They're numbers in Base64 VLQ: each character carries 5 bits of data and a continuation bit. Groups of 1, 4 or 5 numbers give a generated column, a source file, an original line and column, and optionally a name.
Is the source map format standardised?
Yes. Version 3, long a de facto standard, was published by Ecma International as ECMA-426 in December 2024.
How do I fix "DevTools failed to load source map"?
The file names a map that isn't there. Deploy the .map file at the path the comment gives, relative to the JavaScript file, or remove the comment. It only affects people with DevTools open.
Related formats
Other file types explained
Keep going
Related
Sources
- ECMA-426: Source map format specification
- ECMA-426, 1st edition (December 2024), full text
- TC39 source map repository (current draft and proposals)
- Chrome DevTools: View and manually load source maps
Last reviewed 27 October 2026.