Source maps translate minified production code back to readable source code, making error stack traces actionable in Sentry.
Why Source Maps Matter
Without source maps, production errors look like this:
Error: Cannot read property 'x' of undefined
at t.a (bundle.min.js:1:3421)
at Object.r (bundle.min.js:1:7834)
With source maps:
Error: Cannot read property 'x' of undefined
at UserProfile.fetchUser (components/UserProfile.tsx:42:15)
at async renderProfile (pages/profile.tsx:18:5)
Quick Start
Next.js
Source maps are configured automatically:
// next.config.js
const { withSentryConfig } = require ( '@sentry/nextjs' );
module . exports = withSentryConfig (
{
// Your Next.js config
},
{
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
silent: true ,
// Source maps are automatically:
// - Generated during build
// - Uploaded to Sentry
// - Deleted from deployment (v9+)
}
);
In Next.js SDK v9+, client-side source maps are automatically deleted after upload to keep them private.
Vite
npm install @sentry/vite-plugin --save-dev
// vite.config.js
import { sentryVitePlugin } from '@sentry/vite-plugin' ;
export default {
build: {
sourcemap: true , // Enable source maps
} ,
plugins: [
sentryVitePlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
}),
] ,
} ;
Webpack
npm install @sentry/webpack-plugin --save-dev
// webpack.config.js
const { sentryWebpackPlugin } = require ( '@sentry/webpack-plugin' );
module . exports = {
devtool: 'source-map' , // or 'hidden-source-map'
plugins: [
sentryWebpackPlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
}),
],
};
Source Map Types
For Production
// webpack.config.js
module . exports = {
// ✅ Recommended: Full source maps, not exposed to users
devtool: 'hidden-source-map' ,
// Alternative: Source maps without original source code
// devtool: 'nosources-source-map',
};
For Development
module . exports = {
devtool: process . env . NODE_ENV === 'production'
? 'hidden-source-map'
: 'eval-source-map' , // Faster rebuilds
};
Authentication
Auth Token (Recommended)
Create an auth token in Sentry:
Go to Settings → Auth Tokens
Create a token with project:releases scope
Store in environment variable:
# .env.local
SENTRY_AUTH_TOKEN = your-token-here
sentryWebpackPlugin ({
authToken: process . env . SENTRY_AUTH_TOKEN ,
});
Never commit auth tokens to version control. Use environment variables or CI secrets.
API Key (Legacy)
sentryWebpackPlugin ({
authToken: process . env . SENTRY_AUTH_TOKEN , // Preferred
// OR (legacy)
// api_key: process.env.SENTRY_API_KEY,
});
Upload Configuration
Basic Upload
sentryWebpackPlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
// Upload all assets
include: './dist' ,
// Ignore certain files
ignore: [ 'node_modules' , 'webpack.config.js' ],
});
Advanced Options
sentryWebpackPlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
// Source maps location
include: './dist' ,
// URL prefix (how files are referenced in production)
urlPrefix: '~/static/js/' ,
// Delete source maps after upload
filesToDeleteAfterUpload: [ 'dist/**/*.js.map' ],
// Set release name
release: {
name: process . env . RELEASE_VERSION ,
},
// Upload during production builds only
silent: ! process . env . CI ,
});
Release Management
Automatic Release Detection
The plugin tries to detect the release automatically from:
SENTRY_RELEASE environment variable
Git commit SHA
CI environment variables
Manual Release Name
sentryWebpackPlugin ({
// ...
release: {
name: 'my-app@1.2.3' ,
},
});
Matching SDK Release
Ensure your SDK uses the same release:
import * as Sentry from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
release: 'my-app@1.2.3' , // Must match uploaded source maps
});
Source maps won’t work if the release name in Sentry.init() doesn’t match the release used during upload.
URL Prefix Configuration
Same Origin
sentryWebpackPlugin ({
include: './dist' ,
urlPrefix: '~/' , // Files at root: /main.js
});
Nested Path
sentryWebpackPlugin ({
include: './dist' ,
urlPrefix: '~/static/js/' , // Files at: /static/js/main.js
});
CDN Hosting
sentryWebpackPlugin ({
include: './dist' ,
urlPrefix: 'https://cdn.example.com/assets/' ,
});
Multiple Bundles
sentryWebpackPlugin ({
include: [
{ paths: [ './dist/app' ], urlPrefix: '~/app/' },
{ paths: [ './dist/admin' ], urlPrefix: '~/admin/' },
],
});
Debugging Source Maps
Verify Upload
Check if source maps were uploaded:
sentry-cli releases files < release-nam e > list
Validate Source Maps
sentry-cli sourcemaps explain < event-i d >
Common Issues
Source maps not applied to events
Symptoms: Stack traces show minified codeSolutions:
Verify release name matches:
// SDK
Sentry . init ({ release: 'v1.0.0' });
// Upload
sentryWebpackPlugin ({ release: { name: 'v1.0.0' } });
Check URL prefix:
// If files are at https://example.com/js/main.js
sentryWebpackPlugin ({ urlPrefix: '~/js/' });
Ensure source maps are uploaded:
sentry-cli releases files v1.0.0 list
Symptoms: Sentry shows “file not found” in stack tracesSolutions:
Verify urlPrefix matches production URLs
Check that files were uploaded:
sentry-cli releases files < releas e > list
Ensure filenames match exactly (case-sensitive)
Symptoms: Some files have source maps, others don’tSolutions:
Check include paths:
sentryWebpackPlugin ({
include: [
'./dist/app' ,
'./dist/vendor' , // Don't forget vendor bundles
],
});
Verify all builds generate source maps:
// webpack.config.js
devtool : 'source-map' , // For all builds
Framework-Specific Guides
React (Create React App)
npm install @sentry/webpack-plugin --save-dev
// config-overrides.js (with react-app-rewired)
const { sentryWebpackPlugin } = require ( '@sentry/webpack-plugin' );
module . exports = function override ( config ) {
config . plugins . push (
sentryWebpackPlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
include: './build' ,
})
);
return config ;
};
Vue CLI
// vue.config.js
const { sentryWebpackPlugin } = require ( '@sentry/webpack-plugin' );
module . exports = {
configureWebpack: {
devtool: 'source-map' ,
plugins: [
sentryWebpackPlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
include: './dist' ,
}),
],
},
};
Angular
// angular.json
{
"projects" : {
"your-app" : {
"architect" : {
"build" : {
"configurations" : {
"production" : {
"sourceMap" : {
"scripts" : true ,
"styles" : true ,
"hidden" : true
}
}
}
}
}
}
}
}
Then use webpack plugin or upload manually.
Svelte (SvelteKit)
// svelte.config.js
import { sveltekit } from '@sveltejs/kit/vite' ;
import { sentryVitePlugin } from '@sentry/vite-plugin' ;
export default {
plugins: [
sveltekit (),
sentryVitePlugin ({
org: 'your-org' ,
project: 'your-project' ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
}),
] ,
build: {
sourcemap: true ,
} ,
} ;
CI/CD Integration
GitHub Actions
name : Deploy
on :
push :
branches : [ main ]
jobs :
deploy :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v3
- name : Build
run : npm run build
env :
SENTRY_AUTH_TOKEN : ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG : your-org
SENTRY_PROJECT : your-project
- name : Create Sentry release
uses : getsentry/action-release@v1
env :
SENTRY_AUTH_TOKEN : ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG : your-org
SENTRY_PROJECT : your-project
with :
environment : production
version : ${{ github.sha }}
GitLab CI
build :
script :
- npm run build
variables :
SENTRY_AUTH_TOKEN : $SENTRY_AUTH_TOKEN
SENTRY_ORG : your-org
SENTRY_PROJECT : your-project
artifacts :
paths :
- dist/
Manual Upload with Sentry CLI
# Install CLI
npm install @sentry/cli --save-dev
# Create release
sentry-cli releases new "my-app@1.0.0"
# Upload source maps
sentry-cli releases files "my-app@1.0.0" upload-sourcemaps ./dist
# Finalize release
sentry-cli releases finalize "my-app@1.0.0"
# Associate commits
sentry-cli releases set-commits "my-app@1.0.0" --auto
Security Best Practices
Use hidden source maps in production
Prevent exposing source code to users: module . exports = {
devtool: 'hidden-source-map' , // Generates maps without references
};
Delete source maps after upload
Remove source maps from your deployment: sentryWebpackPlugin ({
filesToDeleteAfterUpload: [ 'dist/**/*.map' ],
});
Restrict source map access
In Sentry, limit who can view source code:
Go to Settings → General Settings
Configure “Data Scrubbing”
Enable “Scrub data before sending”
Use separate builds for development
Different source map types for different environments: module . exports = {
devtool: process . env . NODE_ENV === 'production'
? 'hidden-source-map'
: 'eval-source-map' ,
};
Troubleshooting Commands
# List uploaded files
sentry-cli releases files < release-nam e > list
# Validate source maps locally
sentry-cli sourcemaps validate ./dist
# Explain why source maps didn't work for an event
sentry-cli sourcemaps explain < event-i d >
# Upload source maps manually
sentry-cli releases files < releas e > upload-sourcemaps ./dist \
--url-prefix '~/static/js/'
# Delete uploaded files
sentry-cli releases files < releas e > delete --all
Complete Example
// webpack.config.js
const { sentryWebpackPlugin } = require ( '@sentry/webpack-plugin' );
const isProd = process . env . NODE_ENV === 'production' ;
module . exports = {
mode: isProd ? 'production' : 'development' ,
devtool: isProd ? 'hidden-source-map' : 'eval-source-map' ,
plugins: [
isProd && sentryWebpackPlugin ({
org: process . env . SENTRY_ORG ,
project: process . env . SENTRY_PROJECT ,
authToken: process . env . SENTRY_AUTH_TOKEN ,
include: './dist' ,
urlPrefix: '~/' ,
release: {
name: process . env . RELEASE_VERSION || 'development' ,
},
filesToDeleteAfterUpload: [ 'dist/**/*.map' ],
silent: true ,
}),
]. filter ( Boolean ),
};
// src/index.js
import * as Sentry from '@sentry/browser' ;
Sentry . init ({
dsn: '__DSN__' ,
release: process . env . RELEASE_VERSION ,
environment: process . env . NODE_ENV ,
});
Next Steps
Error Handling Best practices for capturing errors
Bundle Size Optimize SDK bundle size