Source Maps

Source Maps for Next.js

Generate and upload production source maps in Next.js so client and server errors resolve to your original TypeScript. Step-by-step setup.

Next.js minifies your production bundles to cut JavaScript size and improve load time. The trade-off is that when an error lands in your dashboard, the stack trace points to _app-abc123.js:52:18401 — a location in the minified bundle, not your actual source code. NextJS source maps solve this: they're compact files that map minified code back to your original .tsx and .ts files, turning cryptic traces into readable stacks that point straight to the line that broke.

For teams running Next.js, source maps aren't optional if you want to debug production errors fast. This guide walks through generating and uploading source maps so every error trace resolves to your real code.

Why Next.js source maps matter

Next.js builds for both the browser (client bundles) and Node.js (server bundles), and both get minified in production. A single error might come from either side, and without source maps you get:

at Object._run (apps-9f2c.js:1:52401)
at Array.map (<anonymous>)
at ProcessQueue (apps-9f2c.js:1:50890)

With source maps, the same error becomes:

at processPayment (src/api/checkout.ts:145:22)
at handleSubmit (src/components/Cart.tsx:89:14)

The difference is hours versus minutes. Plus, source maps let LightTrace's GitHub source links point straight to the failing line in your repo.

Enable source maps in your Next.js build

By default, Next.js generates source maps only in development. To include them in production builds, add one line to next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  productionBrowserSourceMaps: true,
};

module.exports = nextConfig;

This generates .map files alongside your minified bundles in .next/standalone/public (for client code) and .next/standalone/.next/server (for server code). The files are large but stay on your server — they never ship to the browser.

The productionBrowserSourceMaps flag enables source maps for client bundles only. Server source maps are automatically generated in modern Next.js versions (14+) and don't require configuration.

Run npm run build to verify the .map files are generated:

npm run build
# Look for .map files in .next/standalone/public and .next/.next/server
find .next -name "*.map" | head -5

Generate and collect source maps for upload

Before uploading to LightTrace, you need to identify which maps to send. In most setups:

  1. Client source maps live in .next/static/chunks/ or .next/standalone/public/ and correspond to browser errors.
  2. Server source maps live in .next/server/ (or .next/standalone/.next/server) for API routes and server components.

For a clean upload pipeline, extract them before deploying:

#!/bin/bash
# scripts/collect-sourcemaps.sh

RELEASE="${npm_package_version:-$(git rev-parse --short HEAD)}"
MAPS_DIR="dist/sourcemaps"

mkdir -p "$MAPS_DIR"

# Collect client maps
find .next/static -name "*.map" -exec cp {} "$MAPS_DIR/" \;

# Collect server maps
find .next/server -name "*.map" -exec cp {} "$MAPS_DIR/" \;

echo "Collected source maps for release: $RELEASE"

Then reference the directory in your upload script.

Upload to LightTrace during CI/CD

LightTrace accepts source map uploads via the Releases API. Create an upload script in your CI pipeline (GitHub Actions shown here):

name: Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v3
        with:
          node-version: 18

      - run: npm ci
      - run: npm run build

      - name: Collect source maps
        run: bash scripts/collect-sourcemaps.sh

      - name: Upload source maps to LightTrace
        run: |
          RELEASE="web@$(node -p "require('./package.json').version")"
          
          for mapfile in dist/sourcemaps/*.map; do
            curl \
              -X POST \
              -H "Authorization: Bearer ${{ secrets.LIGHTTRACE_API_KEY }}" \
              -F "release=$RELEASE" \
              -F "file=@$mapfile" \
              https://your-lighttrace-host/api/releases/$RELEASE/files/
          done

Replace your-lighttrace-host with your LightTrace instance URL. Generate an API key in the LightTrace dashboard under Settings > API Tokens.

Tag your release with the app name and version (e.g., web@1.2.3). This helps LightTrace match source maps to errors, especially if you run multiple services. Use git rev-parse --short HEAD as a fallback if you don't have semantic versioning yet.

Verify source maps are working

After deploying with source maps, wait for the first error to land in LightTrace, then check:

  1. Dashboard: Open an issue. If the stack trace shows your actual .tsx or .ts file paths and line numbers, source maps are working.
  2. Frame details: Click a frame to see it includes the exact line of code. Without source maps, this shows <unknown>.
  3. GitHub links: If you've configured GitHub source links, frames should link to the exact commit in your repo.

If frames still show minified names like _app-abc.js, check:

  • Release tag mismatch: The tag in your source map upload must match the release tag set in the Sentry SDK. Compare:

    Sentry.init({
      dsn: "https://<key>@your-lighttrace-host/1",
      release: "web@1.2.3", // must match upload tag
    });
  • Missing maps: Verify .map files exist in .next/ after build, and were uploaded to LightTrace.

  • Stale cache: Clear LightTrace's cache by creating a new release tag (bump the version), rebuild, and deploy.

Next.js source maps and your source code strategy

Source maps expose your original code structure to anyone who downloads them. This is usually not a security issue — your production code is already visible to browsers — but follow these practices:

  • Keep maps off the CDN. Maps should live on your server only, never served to the browser. Next.js handles this automatically when using productionBrowserSourceMaps: true.
  • Limit access to the upload API. Use a strong API key and rotate it regularly. Restrict uploads to your CI pipeline's IP if possible.
  • Scrub sensitive data. If your code contains hardcoded secrets or sensitive logic, consider a build step that strips them before upload. LightTrace also offers sensitive data scrubbing to redact values from stack frames.

Troubleshooting missing or incorrect mappings

If a stack trace still shows minified code after upload:

  1. Check the release tag again. Errors must carry the exact release tag you uploaded maps for. Look at the error event in LightTrace and compare the release field to your upload command.
  2. Verify file paths match. Source map files should reference relative paths. If your upload includes dist/sourcemaps/app.map, the minified file reference must be app.js.
  3. Re-upload for the release. Once you upload source maps for a release, LightTrace caches them. If you need to re-upload (e.g., you generated better maps), increment the release version.

Now that you have readable stack traces, the next step is understanding how to read a stack trace to find the root cause. For a broader look at source map strategies across tools, see debugging minified JavaScript. And if you're not capturing Next.js errors yet, the Next.js error tracking guide covers the full setup end-to-end.

Start tracking errors in minutes

Deploy your Next.js app with source maps and watch readable stack traces flow into LightTrace — start free and see your first mapped error in minutes.

Source maps are one of the smallest, highest-ROI investments you can make in debugging production code. A few minutes of setup in your build pipeline turns stack traces from noise into a direct path to the broken line.

Fix your next production error faster

Point any Sentry SDK at LightTrace — free up to 5,000 events/month.