Skip to content

Explore alternatives to client injected route manifest #18713

@logaretm

Description

@logaretm

A customer reported a use-case that is at odds with how we inject the route manifest global into the client side bundles.

Hi Sentry folks! We discovered that Sentry generates a globalThis._sentryRouteManifest object with NextJS with all the Next routes of the app, which ends up in the client bundle loaded in the application. We sometimes have routes for unreleased, confidential features that are behind feature gates and server routes and are otherwise not in the root bundle, but Sentry leaks the existence of these routes in plain text in the root bundle. Is there any way to prevent this?

We suggested disabling the disableManifestInjection flag in the build options, but this use-case will be affecting other customers as well without them knowing.

What is _sentryRouteManifest

Route manifest is an AppRouter only feature, it is a value injected on the client side. The value contains an array of objects containing metadata about the user's app directory routes.

The value looks like this:

export type RouteManifest = {
  /**
   * List of all dynamic routes
   */
  dynamicRoutes: RouteInfo[];

  /**
   * List of all static routes
   */
  staticRoutes: RouteInfo[];

  /**
   * List of ISR/SSG routes (routes with generateStaticParams)
   */
  isrRoutes: string[];
};

For dynamic routes, each entry includes:

  • path: The parameterized route (e.g., /users/:id)
  • regex: A pattern to match concrete URLs against
  • paramNames: Names of dynamic parameters
  • hasOptionalPrefix: For i18n routing patterns

What is it Used For?

Parameterized Route Transaction/Span Grouping

We use the route manifest to convert concrete routes on the client-side into parameterized route patterns, so that transactions can be grouped properly together, otherwise each parameter can result in a unique transaction.

This includes Pageload and client-side navigation spans, has nothing to do with server-side spans.

Disabling the route manifest means we will have very high cardinality for parameterized routes, which will affect user dashboards and queries.

Localized Route Grouping

#17775

PR: #17927

With i18n libraries like next-intl using localePrefix: "as-needed", you get this behavior:

  • Default locale: /foo, /products, /about (no prefix)
  • Other locales: /ar/foo, /en/products, /fr/about (with prefix)

Both /foo and /ar/foo should resolve to the same parameterized route /:locale/foo. So during build time those routes are detected and inserted into the route manifest, and during runtime on the client side, a route will be then matched and adjusted to have consistent prefixes.

Disabling the route manifest means the same routes with the default locale omitted will not match the same page with a different locale, leading to inconsistent grouping and higher cardinality.

Discontinuing ISR/SSG Traces

#18176 #16213

PR: #18192

Client side traces for cached ISR pages need to be detached from the server traces. This issue previously caused all client-side navigations for all users to be attached to the first uncached ISR page. This is because the Sentry meta tags will be the same for all cached renders.

During client-side initialization we lookup the current page in the route manifest and check to see if it is an ISR page, and if so, we skip continued traces from the server-side.

Why we need an alternative

On top of what the customer already mentioned:

  • It adds to the build time since it scans directories and matches code.
  • It adds to the bundle-size and if an app is large enough it could be a very large object.

We need to consider dropping the route manifest by default if possible, or completely replace it with a simpler implementation that addresses all the use-cases for it without breaking them.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions