Repository navigation
feat(core): Add @sentry/core/light sub-path export to reduce import time for lightweight consumers #19885
Description
Problem
@sentry/core has a single barrel entry point (index.js) that eagerly loads 179 ESM modules (~776 KB). This includes:
- AI tracing integrations: OpenAI, Anthropic, Google GenAI, LangChain, LangGraph, Vercel AI SDK (21 files, ~170 KB)
- MCP server integration (14 files, ~160 KB)
- Supabase integration (1 file, ~14 KB)
- Feature flags integrations (3 files, ~8 KB)
- Other unused server-framework-specific code: tRPC, fetch instrumentation, idle spans, etc.
Even @sentry/node-core/light, which was designed to be lightweight, re-exports from the full @sentry/core barrel, forcing consumers to pay the entire import cost.
Measured Impact
On our Bun CLI project (getsentry/cli):
| Configuration | @sentry/core Import Time |
|---|---|
| Full barrel (current) | ~40ms |
| Barrel with 32 unused export lines removed (59 transitive modules, 310 KB) | ~27ms |
That is a 33% improvement just by removing modules that lightweight consumers never use.
Proposal
Add a @sentry/core/light sub-path export (similar to @sentry/node-core/light) that excludes:
- AI tracing integrations (OpenAI, Anthropic, Google GenAI, LangChain, LangGraph, Vercel AI SDK)
- MCP server integration
- Supabase integration
- Feature flags integrations (featureFlagsIntegration, growthbookIntegration)
- Server-framework-specific code (tRPC middleware, fetch instrumentation, idle spans)
- Other heavy modules not needed for basic error/tracing/session/logs usage
Then @sentry/node-core/light could import from @sentry/core/light instead of @sentry/core, further reducing the startup cost of lightweight mode.
Our Patch (for reference)
We are currently removing these 32 export lines from the barrel via bun patch (see getsentry/cli#474):
export { TRACING_DEFAULTS, startIdleSpan } from './tracing/idleSpan.js';
export { _INTERNAL_clearAiProviderSkips, ... } from './utils/ai/providerSkip.js';
export { moduleMetadataIntegration } from './integrations/moduleMetadata.js';
export { captureConsoleIntegration } from './integrations/captureconsole.js';
export { dedupeIntegration } from './integrations/dedupe.js';
export { extraErrorDataIntegration } from './integrations/extraerrordata.js';
export { rewriteFramesIntegration } from './integrations/rewriteframes.js';
export { instrumentSupabaseClient, supabaseIntegration } from './integrations/supabase.js';
export { instrumentPostgresJsSql } from './integrations/postgresjs.js';
export { zodErrorsIntegration } from './integrations/zoderrors.js';
export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter.js';
export { featureFlagsIntegration } from './integrations/featureFlags/featureFlagsIntegration.js';
export { growthbookIntegration } from './integrations/featureFlags/growthbook.js';
export { conversationIdIntegration } from './integrations/conversationId.js';
export { profiler } from './profiling.js';
export { instrumentFetchRequest } from './fetch.js';
export { trpcMiddleware } from './trpc.js';
export { wrapMcpServerWithSentry } from './integrations/mcp-server/index.js';
export { addVercelAiProcessors } from './tracing/vercel-ai/index.js';
export { _INTERNAL_cleanupToolCallSpanContext, ... } from './tracing/vercel-ai/utils.js';
export { toolCallSpanContextMap as ... } from './tracing/vercel-ai/constants.js';
export { instrumentOpenAiClient } from './tracing/openai/index.js';
export { OPENAI_INTEGRATION_NAME } from './tracing/openai/constants.js';
export { instrumentAnthropicAiClient } from './tracing/anthropic-ai/index.js';
export { ANTHROPIC_AI_INTEGRATION_NAME } from './tracing/anthropic-ai/constants.js';
export { instrumentGoogleGenAIClient } from './tracing/google-genai/index.js';
export { GOOGLE_GENAI_INTEGRATION_NAME } from './tracing/google-genai/constants.js';
export { createLangChainCallbackHandler } from './tracing/langchain/index.js';
export { LANGCHAIN_INTEGRATION_NAME } from './tracing/langchain/constants.js';
export { instrumentLangGraph, instrumentStateGraphCompile } from './tracing/langgraph/index.js';
export { LANGGRAPH_INTEGRATION_NAME } from './tracing/langgraph/constants.js';
export { _INTERNAL_FLAG_BUFFER_SIZE, ... } from './utils/featureFlags.js';
We also remove the corresponding re-exports from @sentry/node-core/light/index.js.
Happy to contribute a PR if the approach is accepted.
Activity
linear-code commentedon Mar 19, 2026
JS-1964
Lms24 commentedon Mar 19, 2026
I'm a bit torn on this to be honest. I see the reasoning but my first question is, don't we bundle the SDK when building the CLI? At this point, the import chain shouldn't be a problem anymore? Feels like we're sorta re-inventing tree-shaking (?). As for building, sure, a reduced set of exports might slightly reduce build times but at the expense of more public API and another index file we'd need to keep in sync.
I'm also concerned about specificity, as in: The proposed set of exports works for the CLI but the SDK should not be tailored to one project. I'd like us to carefully evaluate what makes a good set of basic exports that make sense for everyone. The primary consumers are other Sentry packages (i.e. the actual SDKs).
I'm wondering if in the long-run, the better path would be to rely more on specific sub path exports, so that we remove these categories of exports from the main
@sentry/corepath completely in favour of e.g.@sentry/core/ai@sentry/core/integrations/utilsdirectory ->@sentry/core/utils@sentry/core/typesThe main intention of node-core/light was to have an SDK that works without OpenTelemetry. The naming is just incredibly hard and
/lightwas the best we could come up with (because the vast majority of module size comes from all the heavy@opentelemetry/*packages).BYK commentedon Mar 19, 2026
But it is, we tested :)
This is just about automatic barrel imports/exports for convenience. Folks can still import these themselves. This is similar to the browser SDK tree-shaking issue.
This is exactly what we did in our patched version (I'm the real BYK btw not the bot)
Lms24 commentedon Mar 20, 2026
How? If you bundle the SDK code, there are no imports anymore at runtime.
BYK commentedon Mar 20, 2026
You load the modules into memory, parse, and execute them???
mydea commentedon Oct 23, 2026
Thanks for the detailed measurements! Rather than a
/lightentry point, v11 moved the heavy pieces out of the main@sentry/corebarrel: AI integrations now live in@sentry/server-utils, and MCP/tRPC in@sentry/core/server(#20435). If the remaining barrel still shows up in your CLI's startup profile, please open a new issue with fresh numbers.