Execute set up local development workflow with Sentry.
Use when configuring Sentry for development environments,
setting up debug mode, or testing error capture locally.
Trigger with phrases like "sentry local dev", "sentry development",
"debug sentry", "sentry dev environment".
Configure Sentry for local development with environment-aware DSN routing, debug-mode verbosity, full-capture sample rates, beforeSend inspection, Sentry Spotlight for offline event viewing, and sentry-cli source map verification. All configuration uses environment variables so nothing leaks into commits.
Prerequisites
@sentry/node v8+ installed (TypeScript/Node) or sentry-sdk v2+ installed (Python)
Separate Sentry project created for development (different DSN from production)
.env file with SENTRY_DSN_DEV and NODE_ENV=development
Network access to *.ingest.sentry.io (or use Spotlight for fully offline work)
Instructions
Step 1 -- Environment-Aware Configuration
Create an initialization file that routes events to the correct Sentry project based on environment, enables debug logging in dev, and captures 100% of traces locally:
// instrument.mjs — import via: node --import ./instrument.mjs app.mjs
import * as Sentry from '@sentry/node';
const env = process.env.NODE_ENV || 'development';
const isDev = env !== 'production';
Sentry.init({
// Route to dev project locally, prod project in production
dsn: isDev
? process.env.SENTRY_DSN_DEV
: process.env.SENTRY_DSN,
environment: env,
release: isDev ? 'dev-local' : process.env.SENTRY_RELEASE,
// Full capture in dev — you need every event for debugging
tracesSampleRate: isDev ? 1.0 : 0.1,
sampleRate: isDev ? 1.0 : 1.0,
// Verbose SDK output to console in dev
debug: isDev,
// Include PII locally for easier debugging (never in prod)
sendDefaultPii: isDev,
// Sentry Spotlight — shows events in local browser UI
// Install: npx @spotlightjs/spotlight
spotlight: isDev,
beforeSend(event, hint) {
if (isDev) {
const exc = event.exception?.values?.[0];
const label = exc
? `${exc.type}: ${exc.value}`
: event.message || 'event';
console.log(`[Sentry Dev] ${label}`);
console.log(` Tags: ${JSON.stringify(event.tags || {})}`);
}
return event;
},
beforeSendTransaction(event) {
if (isDev) {
const duration = event.timestamp && event.start_timestamp
? ((event.timestamp - event.start_timestamp) * 1000).toFixed(0)
: '?';
console.log(`[Sentry Dev] Transaction: ${event.transaction} (${duration}ms)`);
}
return event;
},
});
Set up environment files to keep DSNs out of source:
Step 3 -- Sentry Spotlight and Offline Development
Sentry Spotlight runs a local sidecar that intercepts Sentry events and displays them in a browser UI at http://localhost:8969 (Spotlight's default port) — no network required:
# Install and run Spotlight sidecar (runs alongside your dev server)
npx @spotlightjs/spotlight
The spotlight: true option in Step 1's Sentry.init() routes events to the local sidecar. This gives you a full Sentry-style event viewer without sending anything to sentry.io.
For fully offline development or CI environments with no Sentry access:
// Offline mode — SDK loads but sends nothing
Sentry.init({
dsn: '', // Empty DSN = all capture calls become no-ops
debug: false, // No debug output since nothing is sent
});
// All Sentry.captureException() and captureMessage() calls still work
// without throwing — your code runs without modification
Test source maps locally before deploying with sentry-cli:
Add a git pre-push hook to prevent hardcoded DSNs from leaking into the repo:
#!/bin/bash
set -e
# .git/hooks/pre-push — block commits with hardcoded DSNs
if grep -rn "ingest\.sentry\.io" --include="*.ts" --include="*.js" \
--exclude-dir=node_modules --exclude-dir=dist src/ lib/; then
echo "ERROR: Hardcoded Sentry DSN found in source. Use environment variables."
exit 1
fi
Output
Environment-aware Sentry.init() routing dev events to a separate Sentry project
Debug logging printing captured events and transaction durations to the console
Verification script confirming captureMessage, captureException, and startSpan work
Sentry Spotlight integration for browsing events locally without network
Source map upload and verification workflow with sentry-cli
Pre-push hook preventing hardcoded DSNs from entering version control
Error Handling
Error
Cause
Solution
Events going to prod project
Wrong DSN loaded for environment
Verify SENTRY_DSN_DEV is set; log process.env.NODE_ENV at startup
Debug output too verbose
debug: true left on in production
Gate with debug: isDev as shown in Step 1
Events not appearing in Spotlight
Sidecar not running
Run npx @spotlightjs/spotlight in a separate terminal
Sentry.flush() times out
No network or invalid DSN
Check DSN, test with curl https://sentry.io/api/0/
Rate-limited during dev
100% sample rate hitting project quota
Use a dedicated dev project with separate quota
Source maps not resolving
Release mismatch between upload and init
Ensure --release in sentry-cli matches release in Sentry.init()
getClient() returns undefined
SDK not initialized before check
Import instrument.mjs via --import flag before any app code
beforeSend dropping events
Returns undefined instead of event
Always return event to keep it, or null to explicitly drop
Examples
TypeScript — Conditional Init Helper
// lib/sentry.ts — reusable initialization for any Node.js app
import * as Sentry from '@sentry/node';
export function initSentry() {
const env = process.env.NODE_ENV || 'development';
const isDev = env !== 'production';
// Option A: Skip Sentry entirely if no dev DSN is configured
if (isDev && !process.env.SENTRY_DSN_DEV) {
console.log('[Sentry] Skipped — no SENTRY_DSN_DEV configured');
return;
}
Sentry.init({
dsn: isDev ? process.env.SENTRY_DSN_DEV : process.env.SENTRY_DSN,
environment: env,
debug: isDev,
tracesSampleRate: isDev ? 1.0 : 0.1,
spotlight: isDev,
sendDefaultPii: isDev,
beforeSend(event) {
if (isDev) {
const exc = event.exception?.values?.[0];
console.log(`[Sentry] ${exc?.type || 'Event'}: ${exc?.value || event.message}`);
}
return event;
},
});
console.log(`[Sentry] Initialized for ${env}`);
}
Python — Environment-Aware Setup
# sentry_config.py — environment-aware initialization
import os
import sentry_sdk
def init_sentry():
env = os.getenv("SENTRY_ENVIRONMENT", "development")
is_dev = env != "production"
dsn = (
os.getenv("SENTRY_DSN_DEV")
if is_dev
else os.getenv("SENTRY_DSN")
)
if is_dev and not dsn:
print("[Sentry] Skipped — no SENTRY_DSN_DEV configured")
return
sentry_sdk.init(
dsn=dsn,
environment=env,
release="dev-local" if is_dev else os.getenv("SENTRY_RELEASE"),
# Full capture in dev
traces_sample_rate=1.0 if is_dev else 0.1,
sample_rate=1.0,
# Verbose SDK logging in dev
debug=is_dev,
# Sentry Spotlight for local event viewing
spotlight=True if is_dev else False,
# Inspect events before they are sent
before_send=_before_send_dev if is_dev else None,
)
print(f"[Sentry] Initialized for {env}")
def _before_send_dev(event, hint):
"""Log events to console during local development."""
exc_info = hint.get("exc_info")
if exc_info:
exc_type, exc_value, _ = exc_info
print(f"[Sentry Dev] {exc_type.__name__}: {exc_value}")
elif event.get("message"):
print(f"[Sentry Dev] Message: {event['message']}")
return event
# verify_sentry.py — verification script
import os
import sentry_sdk
sentry_sdk.init(
dsn=os.getenv("SENTRY_DSN_DEV"),
debug=True,
environment="verification",
spotlight=True,
)
# Test captureMessage
sentry_sdk.capture_message("Dev verification — Python", "info")
# Test captureException
try:
raise ValueError("Dev verification error — Python")
except Exception as e:
event_id = sentry_sdk.capture_exception(e)
print(f"Event ID: {event_id}")
# Test performance span
with sentry_sdk.start_span(op="test", description="verification span"):
import time
time.sleep(0.1)
sentry_sdk.flush()
print("Verification complete — check Sentry dashboard or Spotlight")