Skip to content

Build1 publisher2 min readPublished

Next.js standalone builds move the Sentry source-map upload onto your own build machine

Iurii Rogulia published the Sentry wiring running on his self-hosted Coolify deployment, and it shows what the platform integration was quietly doing: uploading maps during the build, then deleting them before the artifact ships.

The Engineer · Build desk

Illustration accompanying Next.js standalone builds move the Sentry source-map upload onto your own build machine

What happened

  • Iurii Rogulia published the Sentry configuration running on his self-hosted Next.js site behind Coolify, where no platform integration does the observability work for him.
  • His instrumentation.ts runs once per runtime at startup, branching on NEXT_RUNTIME to dynamically import the Edge config, or the Node config plus a separate process-handler module.
  • The DSN host encodes the Sentry region, and Rogulia warns that a US-region DSN pasted into an EU account makes events fail to ingest without any visible error.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure Maps left behind in the served artifact hand the un-minified client bundle to anyone who can request the file, which makes the deletion step a security control rather than housekeeping.
  • constraint Because the upload can only run inside the build that produced the maps, a symbolication gap discovered in production costs a fresh build and redeploy instead of a settings change.
  • capability One re-exported symbol decides whether server-side request errors are observable at all, and a Sentry project missing it produces a quiet issue feed that is indistinguishable from a healthy one.
  • decision Richer frames come with a privacy call that the SDK will not make for you: local variables and default PII buy debuggability by shipping request context and variable values off your server.

The ordering constraint does the design work here. A standalone deploy is a copy operation: `output: "standalone"` emits a self-contained bundle, you copy it into a container, and you start it with `node .next/standalone/server.js` [3]. Anything absent from that copy does not exist at runtime. Anything present in it is reachable by whoever can fetch a static asset [5]. Serving maps beside the bundle is a quiet way to open-source a project. So a `.map` file has exactly one window:

1. The build emits it. 2. The build uploads it to Sentry. 3. The build deletes it before the image is sealed.

Rogulia writes that `@sentry/nextjs` performs both the upload and the deletion, but only when the build is configured for it [6]. His published text stops before the build options themselves, so the option names are the part you still confirm against the SDK version you install. What the post does show in full is the runtime wiring, and that is where a suspiciously calm Sentry project usually comes from.

Next.js runs route handlers and Server Components on Node and middleware on the Edge runtime, so Sentry initialises separately in each [7]. `instrumentation.ts` executes once per runtime at server startup: `register()` branches on `NEXT_RUNTIME` and dynamically imports `sentry.edge.config` for Edge, or `sentry.server.config` plus `instrumentation.node` for Node [8]. The dynamic import is load-bearing. A static one pulls the Node SDK into the Edge bundle, where half its dependencies do not exist [9]. Count the registration file, the two runtime configs and the process-handler module and that is four files standing between you and a captured error [16].

The export sitting below `register()` is `onRequestError = Sentry.captureRequestError`, which attaches Sentry to the framework hook that fires when a route handler, a Server Component render or a Server Action throws [10].

One default is worth reading before you trust a dashboard: `tracesSampleRate` is 0.1 in production against 1.0 in development [12], a tenfold gap, so a path you trace comfortably on your laptop is ten times likelier to be recorded there than in production [15]. `includeLocalVariables` captures variable values inside the frames, which is what turns an undefined-property TypeError into something you can reason about [13].

This is one practitioner's config rather than vendor documentation, so treat the specific values as his. What transfers is the split itself, and that is a property of `output: "standalone"` [3], not of Sentry: the moment the build machine stops being the run machine, every step a platform integration used to perform between them becomes a line in your own pipeline [4].

What to watch

  • The build options that trigger upload and post-upload deletion are not in Rogulia's published text; check their names against the @sentry/nextjs version you install.
  • Whether self-hosting platforms such as Coolify add a build-stage upload hook of the kind Rogulia says Vercel's integration provides.
  • Whether onRequestError survives as the Next.js request-error hook name in later releases, since the wiring depends on that single export.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories