Skip to content

feat(effect): Support v4 beta - #20394

Merged
JPeer264 merged 2 commits into
jp/effect-v4from
jp/effect-v4-core
Apr 21, 2026
Merged

feat(effect): Support v4 beta#20394
JPeer264 merged 2 commits into
jp/effect-v4from
jp/effect-v4-core

Conversation

@JPeer264

Copy link
Copy Markdown
Member

This adds support to Effect v4, but also keeps the compatibility for v3. There is no way that we can unit test against v3, as the devDependencies need to use effect@4 and an updated @effect/vitest version, which is not compatible with Effect v3 (this is added in #20389).

The API for Effect v4 has changed a little, so there are safeguards to detect if it is v3 or v4 and uses the correct API. The good part is that for users nothing changed, so they still can use the same methods in their app as before (ofc, respecting the new Effect v4 API).

Before (Effect v3):

constSentryLive=Layer.mergeAll(Sentry.effectLayer({dsn: '__DSN__',tracesSampleRate: 1.0,enableLogs: true,}),Layer.setTracer(Sentry.SentryEffectTracer),Logger.replace(Logger.defaultLogger,Sentry.SentryEffectLogger),Sentry.SentryEffectMetricsLayer,);

After (Effect v4):

constSentryLive=Layer.mergeAll(Sentry.effectLayer({dsn: '__DSN__',tracesSampleRate: 1.0,enableLogs: true,}),Layer.succeed(Tracer.Tracer,Sentry.SentryEffectTracer),Logger.layer([Sentry.SentryEffectLogger]),Sentry.SentryEffectMetricsLayer,);

Both usages still work and are represented in the E2E tests.

@JPeer264JPeer264 self-assigned this Apr 20, 2026

// Use bracket notation to avoid Webpack static analysis flagging missing exports
// This is important for Effect v3 compatibility.
const MetricModule = Metric;

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little hack I had to do in order to support Effect v3 in the browser. It seems that Webpack checks if snapshotUnsafe is available and fails if it doesn't. snapshotUnsafe is for Effect v4 and is not part of the package. By using MetricModule it is possible to work around this issue.

@JPeer264
JPeer264 marked this pull request as ready for review April 20, 2026 07:09
@github-actions

github-actionsBot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser25.78 kBaddedadded
@sentry/browser - with treeshaking flags24.27 kBaddedadded
@sentry/browser (incl. Tracing)43.65 kBaddedadded
@sentry/browser (incl. Tracing + Span Streaming)45.36 kBaddedadded
@sentry/browser (incl. Tracing, Profiling)48.58 kBaddedadded
@sentry/browser (incl. Tracing, Replay)82.79 kBaddedadded
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags72.29 kBaddedadded
@sentry/browser (incl. Tracing, Replay with Canvas)87.49 kBaddedadded
@sentry/browser (incl. Tracing, Replay, Feedback)99.74 kBaddedadded
@sentry/browser (incl. Feedback)42.59 kBaddedadded
@sentry/browser (incl. sendFeedback)30.45 kBaddedadded
@sentry/browser (incl. FeedbackAsync)35.45 kBaddedadded
@sentry/browser (incl. Metrics)27.07 kBaddedadded
@sentry/browser (incl. Logs)27.2 kBaddedadded
@sentry/browser (incl. Metrics & Logs)27.89 kBaddedadded
@sentry/react27.53 kBaddedadded
@sentry/react (incl. Tracing)45.92 kBaddedadded
@sentry/vue30.61 kBaddedadded
@sentry/vue (incl. Tracing)45.49 kBaddedadded
@sentry/svelte25.8 kBaddedadded
CDN Bundle28.46 kBaddedadded
CDN Bundle (incl. Tracing)44.73 kBaddedadded
CDN Bundle (incl. Logs, Metrics)29.83 kBaddedadded
CDN Bundle (incl. Tracing, Logs, Metrics)45.81 kBaddedadded
CDN Bundle (incl. Replay, Logs, Metrics)68.73 kBaddedadded
CDN Bundle (incl. Tracing, Replay)81.68 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)82.77 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback)87.2 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)88.27 kBaddedadded
CDN Bundle - uncompressed83.12 kBaddedadded
CDN Bundle (incl. Tracing) - uncompressed133.75 kBaddedadded
CDN Bundle (incl. Logs, Metrics) - uncompressed87.27 kBaddedadded
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed137.17 kBaddedadded
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed210.63 kBaddedadded
CDN Bundle (incl. Tracing, Replay) - uncompressed250.99 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed254.38 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed263.9 kBaddedadded
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed267.29 kBaddedadded
@sentry/nextjs (client)48.44 kBaddedadded
@sentry/sveltekit (client)44.09 kBaddedadded
@sentry/node-core57.94 kBaddedadded
@sentry/node174.78 kBaddedadded
@sentry/node - without tracing97.89 kBaddedadded
@sentry/aws-serverless115.12 kBaddedadded

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f6b4de. Configure here.

Comment threadpackages/effect/src/metrics.ts

@s1gr1ds1gr1d left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good 👍

Just a general comment: when trying to differentiate the logic between v3 and v4 you always check for the structure of specific objects. If e.g. in v4 cause.reasons is always an array of Reason objects, you could theoretically just do something like isV4() and then apply the logic. But I am not sure if there is an easy way of finding out the used version (maybe checking the package.json)

@JPeer264

Copy link
Copy Markdown
MemberAuthor

If e.g. in v4 cause.reasons is always an array of Reason objects, you could theoretically just do something like isV4() and then apply the logic. But I am not sure if there is an easy way of finding out the used version (maybe checking the package.json)

I thought for it to make it more generic, but since we do not have any bundler plugin or similar there is no chance to check for it. Effect itself doesn't have a versioning internally, which makes it harder.

Comment on lines +39 to +43
const V3_COUNTER_STATE_TYPE_ID = Symbol.for('effect/MetricState/Counter');
const V3_GAUGE_STATE_TYPE_ID = Symbol.for('effect/MetricState/Gauge');
const V3_HISTOGRAM_STATE_TYPE_ID = Symbol.for('effect/MetricState/Histogram');
const V3_SUMMARY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Summary');
const V3_FREQUENCY_STATE_TYPE_ID = Symbol.for('effect/MetricState/Frequency');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The hardcoded symbols used for Effect v3 metric detection are untested. If they are incorrect, v3 metrics will be silently dropped.
Severity: HIGH

Suggested Fix

Add an E2E test case for the effect-node (v3) application that specifically sends and verifies metrics. This will validate that the hardcoded symbol keys are correct and that metrics are being reported as expected for Effect v3 users.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: packages/effect/src/metrics.ts#L39-L43
Potential issue: The code uses hardcoded, globally-registered symbols (e.g.,
`Symbol.for('effect/MetricState/Counter')`) to detect Effect v3 metric types. This logic
is not covered by any unit or E2E tests, as the test suite only runs against Effect v4.
If these symbol keys do not exactly match the internal symbols used by Effect v3, the
`sendV3MetricToSentry` function will fail to identify any metrics, causing them to be
silently dropped without any errors or warnings.

Also affects:

  • packages/effect/src/metrics.ts:71~94

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests will come soon!

@JPeer264
JPeer264 merged commit dc49c22 into jp/effect-v4Apr 21, 2026
240 checks passed
@JPeer264
JPeer264 deleted the jp/effect-v4-core branch April 21, 2026 07:44
JPeer264 added a commit that referenced this pull request Apr 21, 2026
This adds support to Effect v4, but also keeps the compatibility for v3.
There is no way that we can unit test against v3, as the
`devDependencies` need to use `effect@4` and an updated `@effect/vitest`
version, which is not compatible with Effect v3 (this is added in
The API for Effect v4 has changed a little, so there are safeguards to
detect if it is v3 or v4 and uses the correct API. The good part is that
for users nothing changed, so they still can use the same methods in
their app as before (ofc, respecting the new Effect v4 API).
Before (Effect v3):
```ts
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.setTracer(Sentry.SentryEffectTracer),
Logger.replace(Logger.defaultLogger, Sentry.SentryEffectLogger),
Sentry.SentryEffectMetricsLayer,
);
```
After (Effect v4):
```js
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.succeed(Tracer.Tracer, Sentry.SentryEffectTracer),
Logger.layer([Sentry.SentryEffectLogger]),
Sentry.SentryEffectMetricsLayer,
);
```
Both usages still work and are represented in the E2E tests.
JPeer264 added a commit that referenced this pull request Apr 21, 2026
This adds support to Effect v4, but also keeps the compatibility for v3.
There is no way that we can unit test against v3, as the
`devDependencies` need to use `effect@4` and an updated `@effect/vitest`
version, which is not compatible with Effect v3 (this is added in
The API for Effect v4 has changed a little, so there are safeguards to
detect if it is v3 or v4 and uses the correct API. The good part is that
for users nothing changed, so they still can use the same methods in
their app as before (ofc, respecting the new Effect v4 API).
Before (Effect v3):
```ts
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.setTracer(Sentry.SentryEffectTracer),
Logger.replace(Logger.defaultLogger, Sentry.SentryEffectLogger),
Sentry.SentryEffectMetricsLayer,
);
```
After (Effect v4):
```js
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.succeed(Tracer.Tracer, Sentry.SentryEffectTracer),
Logger.layer([Sentry.SentryEffectLogger]),
Sentry.SentryEffectMetricsLayer,
);
```
Both usages still work and are represented in the E2E tests.
JPeer264 added a commit that referenced this pull request Apr 21, 2026
This adds support to Effect v4, but also keeps the compatibility for v3.
There is no way that we can unit test against v3, as the
`devDependencies` need to use `effect@4` and an updated `@effect/vitest`
version, which is not compatible with Effect v3 (this is added in
The API for Effect v4 has changed a little, so there are safeguards to
detect if it is v3 or v4 and uses the correct API. The good part is that
for users nothing changed, so they still can use the same methods in
their app as before (ofc, respecting the new Effect v4 API).
Before (Effect v3):
```ts
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.setTracer(Sentry.SentryEffectTracer),
Logger.replace(Logger.defaultLogger, Sentry.SentryEffectLogger),
Sentry.SentryEffectMetricsLayer,
);
```
After (Effect v4):
```js
const SentryLive = Layer.mergeAll(
Sentry.effectLayer({
dsn: '__DSN__',
tracesSampleRate: 1.0,
enableLogs: true,
}),
Layer.succeed(Tracer.Tracer, Sentry.SentryEffectTracer),
Logger.layer([Sentry.SentryEffectLogger]),
Sentry.SentryEffectMetricsLayer,
);
```
Both usages still work and are represented in the E2E tests.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@JPeer264@s1gr1d