Crossdeck University
Watch — turn minified gibberish into your real file and line Film in production
0:00 / 0:00
Lesson 3 of 5 · Errors

Source maps

In production your code is minified, so a crash points at main.4f3a.js:1:88421 — useless. Source maps translate that back to your real file and line. Upload them per build, and Crossdeck does the rest.

5 min CLI · CI

When you're done: every production error shows readable file paths and line numbers, not minified gibberish.

1 What this is & why it matters

A stack trace you can't read isn't worth much

Everything you set up in the last two lessons — captured errors, rich context — lands on a stack trace. But in production that trace points into minified bundles, so the line that broke reads like t.4f3a.js:1:88421. Source maps are the translation table back to checkout.ts:42.

Crossdeck applies them server-side: you upload the maps at build time, and every trace renders readable from then on. One safety note up front — you upload the maps privately to Crossdeck and delete them from your public bundle, so you get readable traces without exposing your source to the world.

2 How to wire it

Upload per build, stamp the release on every event

Four steps. Install the CLI, have your bundler emit external maps (with sourcesContent inlined), then upload after each production build:

npm install --save-dev @cross-deck/cli

# after your production build:
npx @cross-deck/cli upload-sourcemaps \
  --release "$GIT_SHA" \
  --url-prefix https://your.app/assets/ \
  ./dist

# don't ship maps to users — remove them from the public bundle:
find dist -name '*.map' -delete

Then stamp the same release identifier on every event, so Crossdeck knows which build an error came from:

Crossdeck.init({
  publishableKey: "cd_pk_live_…",
  appVersion: process.env.GIT_SHA,   // the SAME value you uploaded under
});
3 How it works, piece by piece

The release identifier is the join key

The whole thing hinges on one value matching in two places. The upload files your maps under --release "$GIT_SHA". Every event you send is stamped with appVersion. When an error arrives, Crossdeck looks up the maps for that release and rewrites the minified trace into your original source — file, line, and column.

So the one rule: use the same release identifier in both the upload and the SDK init. If the upload says abc123 but your events are stamped def456, there's nothing to match and you're back to minified traces. A commit SHA is the natural choice because it's unique per build and you already have it in CI.

4 The green result in your dashboard

Readable traces, straight from production

Throw a test error — throw new Error("crossdeck sourcemap test") — from your built app, and open the issue. The stack trace points at your real file and line, the way it would in dev. Every production error from here on is just as readable.

app.cross-deck.com · issues · stack trace
checkout.ts:42 · readable

Was main.4f3a.js:1:88421 — now checkout.ts:42:18, mapped by release $GIT_SHA. No more guessing.

Install @cross-deck/cli, emit external maps, and upload-sourcemaps --release "$GIT_SHA" after each build — then delete the maps from your public bundle. Stamp the same value as appVersion in init(). The release identifier is the join key; match it in both places and Crossdeck renders your real source.