Skip to content

Engineering

Production source maps with Vite: what each setting really ships

We built one module with each of Vite's three source map settings and threw an error from each build. One gave a useless stack frame; the other two shipped our whole source code in a file.

Andrew Babo4 min read

Share
On this page
Production source maps with Vite: what each setting really ships

Vite does not generate source maps for production builds unless you ask. With true or hidden it writes a .map file next to each bundle that contains your complete original source code. The only difference is that hidden leaves out the comment pointing to it.

So the safe setup is to generate maps, upload them to your error tracker, and delete them before you deploy. We checked each setting on 26 October 2026 with Vite 8.1.5.

The test#

One small module computes an order total and throws when an item has no price. We built it three times with build.sourcemap set to false, true and "hidden", minified, called the function, and read the first frame of the stack trace.

JavaScript
function priceOf(item) {  if (item.price == null) {    throw new Error(`Missing price for ${item.sku}`);  }  return Math.round(item.price * 100);}

Then we fed that frame through each build's map, the same way an error tracker does.

What each setting produced#

Vite's three source map settings compared on the same build
Lab 26 Oct 2026 · Vite 8.1.5, minified library build
build.sourcemapFiles writtenComment in the bundleStack frameSource readable from the map
false (the default)app.mjsnoapp.mjs:6:29, nothing to resolve it withno map
trueapp.mjs, app.mjs.mapyesresolves to src/checkout.js:8yes, all of it
"hidden"app.mjs, app.mjs.mapnoresolves to src/checkout.js:8yes, all of it

The default matches Vite's docs: “Default: false”. The frame app.mjs:6:29 is all you get. In a real app, with hundreds of functions packed onto a few lines, that tells you almost nothing.

With a map, the same frame resolved to line 8 of src/checkout.js, the throw inside priceOf. Both maps were identical and both carried a sourcesContent field with the full original file, comments included. The source map standard calls that field “an optional list of source content”, and Vite fills it in.

A minified stack frame and the same frame after resolving it through the map
Lab 26 Oct 2026 · 3 builds, same result each time

What hidden does and does not do#

Vite describes hidden as working “like true except that the corresponding sourcemap comments in the bundled files are suppressed”. Browsers then do not load the map on their own, and DevTools will not show your source.

The .map file is still in your output folder. If you deploy that folder, a static host serves it to anyone who asks for app.mjs.map. File names are easy to guess, because the map's name is the bundle's name plus .map. hidden hides the pointer, not the file.

The setup we recommend#

  1. Generate maps in CI, with hidden so no bundle points at a map.
  2. Mark the bundles and maps so they can find each other. A tool such as sentry-cli sourcemaps inject writes a Debug ID into each bundle and its map. Sentry's docs define them as “globally unique ids that identify a transformed JavaScript file and its associated source map”.
  3. Upload the maps to your error tracker, tagged with the same release your SDK reports.
  4. Delete the .map files before deploying, or tell your host not to serve them.
  5. Throw one test error in the new release and check that the frames show your file names.

Step 2 must run on the exact files you deploy. If you inject IDs, then rebuild, the IDs no longer match and frames stay minified.

Where Belvador fits#

Belvador accepts maps through sentry-cli's upload API or a tarball, stores them on your own node and never publishes them with your site. Your node matches each frame to a map by Debug ID. The source maps guide has the CI commands, the upload token setup and the checks to run when frames stay minified. The React SDK guide sets the release value the upload must match, and the React page shows the full setup.

Keep reading#

Part of the guide: JavaScript error handling for AI-generated apps: where errors escape

All posts

Read next in the docs

See your own production errors this way

Belvador runs on your own Hetzner server: errors, cron jobs, uptime and traces, with your data staying yours.