Migrate from 8.x to 9.x

Learn about migrating from Sentry JavaScript SDK 8.x to 9.x

Version 9 of the Sentry JavaScript SDK primarily introduces API cleanup and version support changes.

This update contains behavioral changes that will not be caught by type checkers, linters, or tests, so we recommend carefully reading through the entire migration guide instead of relying on automatic tooling.

Version 9 of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v8). Lower versions may continue to work, but may not support all features.

Version 9 of the Sentry SDK has new compatibility ranges for runtimes and frameworks.

All the JavaScript code in the Sentry SDK packages may now contain ECMAScript 2020 features. This includes features like Nullish Coalescing (??), Optional Chaining (?.), String.matchAll(), Logical Assignment Operators (&&=, ||=, ??=), and Promise.allSettled().

If you observe failures due to syntax or features listed above, it may indicate that your current runtime does not support ES2020. If your runtime does not support ES2020, we recommend transpiling the SDK using Babel or similar tools.

The minimum supported Node.js version is 18.0.0 (Released Apr 19, 2022), except for ESM-only SDKs (@sentry/astro, @sentry/nuxt, @sentry/sveltekit) which require Node.js version 18.19.1 (Released Feb 14, 2024) or higher.

The minimum supported Deno version is now 2.0.0.

  • SvelteKit version 1.x is no longer supported.

In preparation for v2 of the OpenTelemetry SDK, the minimum required TypeScript version is increased to version 5.0.4.

Additionally, like the OpenTelemetry SDK, the Sentry JavaScript SDK will follow DefinitelyType's version support policy which has a support time frame of 2 years for any released version of TypeScript.

Older TypeScript versions may continue to be compatible, but no guarantees apply.

  • Prisma version 5.x and below are no longer supported (minimum supported version is 6.x).

The changes outlined in this section describe in what way the SDK may behave differently after upgrading:

  • Dropping spans in the beforeSendSpan hook is no longer possible. This means you can no longer return null from the beforeSendSpan hook. This hook is intended to be used to add additional data to spans or remove unwanted attributes (for example for PII stripping). To control which spans are recorded, we recommend configuring integrations instead.

  • The beforeSendSpan hook now receives the root span as well as the child spans. We recommend checking your beforeSendSpan to account for this change.

  • The request property on the samplingContext argument passed to the tracesSampler and profilesSampler options has been removed. samplingContext.normalizedRequest can be used instead. Note that the type of normalizedRequest differs from request.

  • The startSpan behavior was changed if you pass a custom scope: While in v8, the passed scope was set active directly on the passed scope, in v9, the scope is cloned. This behavior change does not apply to @sentry/node where the scope was already cloned. This change was made to ensure that the span only remains active within the callback and to align behavior between @sentry/node and all other SDKs. As a result of the change, span hierarchy should be more accurate. However, modifying the scope (for example, set tags) within the startSpan callback behaves a bit differently now.

    Copied
    startSpan({ name: "example", scope: customScope }, () => {
      // This tag will only remain within the callback.
      getCurrentScope().setTag("tag-a", "a");
    
      // Set the tag directly on customScope in addition,
      // if you want to to persist the tag outside of the callback.
      customScope.setTag("tag-a", "a");
    });
    
  • Passing undefined as a tracesSampleRate option value will now be treated the same as if the attribute was not defined at all. In previous versions, it was checked whether the tracesSampleRate property existed in the SDK options to decide if trace data should be propagated for tracing. Consequentially, this sometimes caused the SDK to propagate negative sampling decisions when tracesSampleRate: undefined was passed. This is no longer the case and sampling decisions will be deferred to downstream SDKs for distributed tracing. This is more of a bugfix rather than a breaking change, however, depending on the setup of your SDKs, an increase in sampled traces may be observed.

  • If you use the optional captureConsoleIntegration and set attachStackTrace: true in your Sentry.init call, console messages will no longer be marked as unhandled (handled: false) but as handled (handled: true). If you want to keep sending them as unhandled, configure the handled option when adding the integration:

    Copied
    Sentry.init({
      integrations: [Sentry.captureConsoleIntegration({ handled: false })],
      attachStackTrace: true,
    });
    

The @sentry/utils package will no longer be published.

The @sentry/types package will continue to be published, however, it is deprecated and its API will not be extended. It will not be published as part of future major versions.

All exports and APIs of @sentry/utils and @sentry/types (except for the ones that are explicitly called out in this migration guide to be removed) have been moved into the @sentry/core package.

The changes outlined in this section detail deprecated APIs that are now removed.

  • The metrics API has been removed from the SDK.

    The Sentry metrics beta has ended and the metrics API has been removed from the SDK. Learn more in the Sentry help center docs.

  • The transactionContext property on the samplingContext argument passed to the tracesSampler and profilesSampler options has been removed. All object attributes are available in the top-level of samplingContext:

    Copied
    Sentry.init({
      // Custom traces sampler
      tracesSampler: samplingContext => {
    -   if (samplingContext.transactionContext.name === '/health-check') {
    +   if (samplingContext.name === '/health-check') {
          return 0;
        } else {
          return 0.5;
        }
      },
    
      // Custom profiles sampler
      profilesSampler: samplingContext => {
    -   if (samplingContext.transactionContext.name === '/health-check') {
    +   if (samplingContext.name === '/health-check') {
          return 0;
        } else {
          return 0.5;
        }
      },
    })
    
  • The enableTracing option was removed. Instead, set tracesSampleRate: 1 or tracesSampleRate: 0.

  • The autoSessionTracking option was removed.

    To enable session tracking, ensure that either, in browser environments the browserSessionIntegration is added, or in server environments the httpIntegration is added. (both are added by default)

    To disable session tracking, remove the browserSessionIntegration in browser environments, or in server environments configure the httpIntegration with the trackIncomingRequestsAsSessions option set to false. Additionally, in Node.js environments, a session was automatically created for every node process when autoSessionTracking was set to true. This behavior has been replaced by the processSessionIntegration which is configured by default.

  • The getCurrentHub(), Hub and getCurrentHubShim() APIs have been removed. They were on compatibility life support since the release of v8 and have now been fully removed from the SDK.

  • The addOpenTelemetryInstrumentation method has been removed. Use the openTelemetryInstrumentations option in Sentry.init() or your custom Sentry Client instead.

    Copied
    import * as Sentry from "@sentry/node";
    
    // before
    Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation());
    
    // after
    Sentry.init({
      openTelemetryInstrumentations: [new GenericPoolInstrumentation()],
    });
    
  • The debugIntegration has been removed. To log outgoing events, use Hook Options (beforeSend, beforeSendTransaction, ...).

  • The sessionTimingIntegration has been removed. To capture session durations alongside events, use Context (Sentry.setContext()).

  • The CJS code for the SDK now only contains compatibility statements for CJS/ESM in modules that have default exports:

    Copied
    Object.defineProperty(exports, "__esModule", { value: true });
    

    Let us know if this is causing issues in your setup by opening an issue on GitHub.

  • @sentry/deno is no longer published on the deno.land registry, so you'll need to import the SDK from npm:

    Copied
    import * as Sentry from "npm:@sentry/deno";
    
    Sentry.init({
      dsn: "__DSN__",
      // ...
    });
    

  • Scope usages now always expect Scope instances.

  • Client usages now always expect BaseClient instances. The abstract Client class was removed. Client classes now have to extend from BaseClient.

These changes should not affect most users unless you relied on passing things with a similar shape to internal methods.

In v8, interfaces have been exported from @sentry/types, while implementations have been exported from other packages.

The following changes are unlikely to affect users of the SDK. They are listed here only for completion sake, and to alert users that may be relying on internal behavior.

  • A sampleRand field on PropagationContext is now required. This is relevant if you used scope.setPropagationContext(...)

  • The DEFAULT_USER_INCLUDES constant has been removed. There is no replacement.

  • The BAGGAGE_HEADER_NAME export has been removed. Use a "baggage" string constant directly instead.

  • The extractRequestData method has been removed. Manually extract relevant data of request objects instead.

  • The addRequestDataToEvent method has been removed. Use httpRequestToRequestData instead and put the resulting object directly on event.request.

  • The addNormalizedRequestDataToEvent method has been removed. Use httpRequestToRequestData instead and put the resulting object directly on event.request.

  • The generatePropagationContext() method was removed. Use generateTraceId() directly.

  • The spanId field on propagationContext was removed. It was replaced with an optional field propagationSpanId having the same semantics but only being defined when a unit of execution should be associated with a particular span ID.

  • The initSessionFlusher method on the ServerRuntimeClient was removed without replacements. Any mechanisms creating sessions will flush themselves.

  • The IntegrationClass type was removed. Instead, use Integration or IntegrationFn.

  • The following exports have been removed without replacement:

    • getNumberOfUrlSegments
    • validSeverityLevels
    • makeFifoCache
    • arrayify
    • flatten
    • urlEncode
    • getDomElement
    • memoBuilder
    • extractPathForTransaction
    • _browserPerformanceTimeOriginMode
    • addTracingHeadersToFetchRequest
    • SessionFlusher
  • The following types have been removed without replacement:

    • Request RequestEventData
    • TransactionNamingScheme
    • RequestDataIntegrationOptions
    • SessionFlusherLike
    • RequestSession
    • RequestSessionStatus
  • client._prepareEvent() now requires both currentScope and isolationScope to be passed as arguments.

  • client.recordDroppedEvent() no longer accepts an event as a third argument. The event was no longer used for some time, instead you can (optionally) pass a count of dropped events as a third argument.

Version support timelines are stressful for everybody using the SDK, so we won't be defining one. Instead, we will be applying bug fixes and features to older versions as long as there is demand.

Additionally, we hold ourselves accountable to any security issues, meaning that if any vulnerabilities are found, we will in almost all cases backport them.

Note, that backporting decisions are made on a case-by-case basis. If you need a fix or feature in a previous version of the SDK, please reach out via a GitHub Issue.

Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").