Replace an existing error tracking tool (Rollbar, Bugsnag, New Relic, Raygun, Airbrake) with Sentry using a phased migration that runs both tools in parallel before cutover. This skill covers concept mapping between providers, SDK swap patterns, alert rule migration, team training, and rollback strategy.
!npm list 2>/dev/null | command grep -iE "sentry|rollbar|bugsnag|raygun|airbrake|honeybadger|newrelic" || echo 'No error tracking packages found'
Build a translation table mapping the current tool's terminology and API surface to Sentry equivalents. Scan the codebase for all calls to the existing SDK.
| Concept | Rollbar | Bugsnag | New Relic | Sentry |
|---|---|---|---|---|
| Capture error | rollbar.error(err) |
Bugsnag.notify(err) |
newrelic.noticeError(err) |
Sentry.captureException(err) |
| Log message | rollbar.info(msg) |
Bugsnag.notify(msg) |
newrelic.recordCustomEvent() |
Sentry.captureMessage(msg) |
| User context | rollbar.configure({ person: {...} }) |
Bugsnag.setUser(id, email) |
newrelic.setUserID(id) |
Sentry.setUser({ id, email }) |
| Tags/metadata | rollbar.configure({ custom: {...} }) |
bugsnag.addMetadata(tab, data) |
newrelic.addCustomAttributes() |
Sentry.setTag() / Sentry.setContext() |
| Breadcrumbs | rollbar.log(level, msg) |
Bugsnag.leaveBreadcrumb(msg) |
N/A | Sentry.addBreadcrumb({ message }) |
| Release tracking | code_version config |
appVersion config |
NEW_RELIC_LABELS |
Sentry.init({ release: 'v1.2.3' }) |
| Environment | environment config |
releaseStage config |
NEW_RELIC_APP_NAME suffix |
Sentry.init({ environment: 'prod' }) |
| Error filter | checkIgnore callback |
onError callback |
ignore_errors config |
beforeSend hook |
| Performance | N/A | @bugsnag/plugin-* |
Built-in APM | Built-in tracesSampleRate |
Use Grep to find all references: grep -rn "rollbar\|Bugsnag\|newrelic\|noticeError" --include="*.ts" --include="*.js" src/
Install the Sentry SDK alongside the existing tool. Route errors to both destinations during the transition period to validate parity before removing the old tool.
// instrument.ts -- load BEFORE any other import
import * as Sentry from '@sentry/node';
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
release: process.env.npm_package_version, // auto-read from package.json
tracesSampleRate: 0.1, // start low, tune after baseline
sendDefaultPii: false,
});
// dual-reporter.ts -- send to BOTH tools during parallel run
import * as Sentry from '@sentry/node';
// Keep existing tool import (e.g., Rollbar, Bugsnag)
import Rollbar from 'rollbar';
const rollbar = new Rollbar({ accessToken: process.env.ROLLBAR_TOKEN });
export function captureError(error: Error, context?: Record<string, unknown>) {
// Sentry (new)
Sentry.withScope((scope) => {
if (context) scope.setContext('migration', context);
Sentry.captureException(error);
});
// Old tool (keep running until parity verified)
rollbar.error(error, context);
}
export function setUserContext(user: { id: string; email?: string }) {
Sentry.setUser(user);
rollbar.configure({ payload: { person: { id: user.id, email: user.email } } });
}
Export alert rules from the old tool. Map each alert to a Sentry equivalent:
environment:production and action "Send Slack notification".Validate parity during the parallel run window:
# Compare error counts -- Sentry API
curl -s -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
"https://sentry.io/api/0/projects/$SENTRY_ORG/$SENTRY_PROJECT/stats/" | jq '.[] | .total'
# Compare with old tool API (Rollbar example)
curl -s -H "X-Rollbar-Access-Token: $ROLLBAR_TOKEN" \
"https://api.rollbar.com/api/1/reports/top_recent_items" | jq '.result | length'
Remove the old SDK after parity is confirmed:
npm uninstall rollbar @bugsnag/node @bugsnag/plugin-express newrelic || echo "Some packages not found (expected if only one tool was installed)"
Search for leftover references and remove them:
grep -rn "rollbar\|bugsnag\|newrelic\|raygun\|airbrake" \
--include="*.ts" --include="*.js" --include="*.env*" \
--exclude-dir=node_modules . || echo "No remaining references found"
Schedule team training: walk through the Sentry dashboard (Issues, Performance, Releases views), show how to assign issues, and demonstrate the alert configuration UI.
Rollback strategy: keep the old tool's npm package in devDependencies and its configuration file in a migration-backup/ directory for 30 days after cutover. If Sentry surfaces fewer errors than expected, re-enable dual reporting and investigate.
| Error | Cause | Solution |
|---|---|---|
| Error count mismatch between tools | Different sampling rates or filter rules | Set both tools to 100% sampling during parallel run; disable beforeSend filters temporarily |
| Missing stack traces in Sentry | Source maps not uploaded | Run sentry-cli sourcemaps upload --release=$(npm pkg get version) in CI |
| Old tool references remain after removal | Incomplete codebase search | Run grep across all file types including .env, CI configs, and infrastructure-as-code |
| Sentry alerts not firing | Alert conditions misconfigured | Test with a synthetic error: Sentry.captureException(new Error('alert-test')) and verify delivery |
| New Relic APM data missing after switch | Sentry replaces error tracking only, not full APM | Keep New Relic for APM if needed; Sentry Performance covers traces but not infrastructure metrics |
| Team unfamiliar with Sentry UI | No training provided | Schedule 30-minute walkthrough covering Issues, Performance, and Releases views |
Migrate Express app from Rollbar to Sentry:
// BEFORE: rollbar error handler middleware
import Rollbar from 'rollbar';
const rollbar = new Rollbar({ accessToken: process.env.ROLLBAR_TOKEN });
app.use(rollbar.errorHandler());
// AFTER: Sentry error handler middleware
import * as Sentry from '@sentry/node';
Sentry.init({ dsn: process.env.SENTRY_DSN });
Sentry.setupExpressErrorHandler(app);
Migrate React error boundary from Bugsnag to Sentry:
// BEFORE: Bugsnag React initialization + error boundary
import Bugsnag from '@bugsnag/js';
import BugsnagPluginReact from '@bugsnag/plugin-react';
Bugsnag.start({ plugins: [new BugsnagPluginReact()] });
const ErrorBoundary = Bugsnag.getPlugin('react')!.createErrorBoundary(React);
// Usage: wrap root component with ErrorBoundary
// AFTER: Sentry React initialization + error boundary
import * as Sentry from '@sentry/react';
Sentry.init({ dsn: process.env.SENTRY_DSN });
// Usage: wrap root component with Sentry.ErrorBoundary (accepts fallback prop)
// See @sentry/react docs for ErrorBoundary component API
Post-migration verification script:
import * as Sentry from '@sentry/node';
async function verifyMigration() {
const eventId = Sentry.captureException(new Error('Migration verification test'));
console.log('Error captured:', eventId ? 'PASS' : 'FAIL');
Sentry.captureMessage('Migration complete', 'info');
const flushed = await Sentry.flush(5000);
console.log('Events delivered:', flushed ? 'PASS' : 'FAIL');
}
verifyMigration();
After migration, proceed to sentry-performance-tracing to configure distributed tracing, or sentry-prod-checklist to verify production readiness.