Skip to content

feat(Engine): Enable Flag Dependency in the Node.js server-side SDK - #311

Open
linear-code[bot] wants to merge 3 commits into
mainfrom
linear/sdk-10-enable-flag-dependency-in-the-nodejs-server-side-sdk-5aca
Open

linear-code[bot] wants to merge 3 commits into
mainfrom
linear/sdk-10-enable-flag-dependency-in-the-nodejs-server-side-sdk-5aca

Conversation

@linear-code

@linear-code linear-code Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Contributes to SDK-10

With local evaluation, segments can now depend on other flags ($.flags.<feature>.enabled, .value, .variant), the same way as flagsmith-engine#343, which edge-api uses. To pass engine-test-data v3.12.1, the engine also needed the other changes in flagsmith-engine 11.1.1.

  • A flag can be targeted on whether another flag is enabled, or on its value or variant. Chains of dependencies are followed.
  • Flags caught in a dependency cycle serve their environment default, with the reason ERROR; code=CIRCULAR_DEPENDENCY.
  • Flags that no segment targets now report the STATIC reason instead of DEFAULT.
  • Flag results include the multivariate variant that was selected.
  • Segments are now evaluated even when there is no identity. Environment flags are still evaluated without segments, as in the Python SDK.
  • Fixed npm run generate-engine-types, which runs in the pre-commit hook. The upstream context schema now refers to the result schema, so the script was failing on main.
  • Local evaluation without flag dependencies is as fast as before, measured with the new npm run bench. Details below.

Reviewer notes:

Review effort: 4/5

How did you test this code?

  • All 220 engine-test-data v3.12.1 cases pass. Before this change, 133 failed, including all 19 flag-dependency cases.
  • New SDK tests: a flag that follows its prerequisite under local identity evaluation, and environment flags not picking up segment overrides.
  • npm test: 483 tests pass. npm run test:esm-build: 473 pass, 10 skipped. tsc is clean, and prettier is clean on the changed files.

Performance

Baseline is c9f5df1 (main, before this PR). Both revisions ran the same bench file against the same engine-test-data v3.12.1 checkout. Runs alternated baseline/PR for 5 rounds, and each figure below is the median of the 5 per-round means. Setup: Node 24.22, 1 vCPU sandbox.

Workload (one iteration) Baseline µs PR µs Change
engine-test-data: 202 contexts that don't read flags 2058 1925 −6%
engine-test-data: 18 contexts that read flags 10.7 61.6 +478%
SDK offline, tests/sdk/data/environment.json: environment flags 3.4 3.4 −2%
SDK offline, tests/sdk/data/environment.json: identity flags 18.8 17.6 −6%
SDK offline, 100 features, 50 segments: environment flags 42.4 37.4 −12%
SDK offline, 100 features, 50 segments: identity flags 83.5 83.5 0%
SDK offline, same + a chain of 10 flag dependencies: identity flags 90.3 108.7 +20%
  • Without flag dependencies, every workload is the same or faster. Two optimisations got the PR there:
    • JSONPaths made only of member names are resolved without jsonpath-plus.
    • Segments are no longer evaluated twice when they are read through a dependency.
  • The flag-dependency rows don't compare like for like. The baseline doesn't support Flag Dependency: it evaluates those conditions as non-matching and returns wrong flags.
    • The engine-test-data row is cheap on the baseline mostly because it skipped segments for contexts without an identity.
    • The extra time is the dependent flags actually being resolved.
  • Limitations:
    • These are microbenchmarks of in-process evaluation on a single shared vCPU. Per-round spread was ±1–3%, and up to ±10% on the 202-context row, so differences under about 3% are within noise.
    • A longer standalone loop (50k identity evaluations of the 50-segment environment, outside vitest) put the PR about 3–4% slower than baseline. Profiling attributes about 2 µs of that to computing which features any segment targets, which the STATIC/DEFAULT reason needs. flagsmith-engine computes it the same way.
    • No production-sized environment documents or end-to-end SDK latency were measured.

To reproduce:

npm run bench -- --outputJson pr.json
git worktree add ../baseline c9f5df1 && cd ../baseline
ln -s "$OLDPWD/node_modules" node_modules
rmdir tests/engine/engine-tests/engine-test-data
ln -s "$OLDPWD/tests/engine/engine-tests/engine-test-data" tests/engine/engine-tests/engine-test-data
mkdir -p tests/benchmarks && cp "$OLDPWD/tests/benchmarks/engine.bench.ts" tests/benchmarks/
npx vitest bench --run --compare "$OLDPWD/pr.json"

Port Flag Dependency from flagsmith-engine 11.1.1. Segment conditions
can read other flags' evaluated results through `$.flags.<feature>`
JSONPath properties, resolved lazily and transitively. Flags caught in a
dependency cycle report `ERROR; code=CIRCULAR_DEPENDENCY`.

Align the rest of the engine with flagsmith-engine 11.1.1, as required
by engine-test-data v3.12.1:
- Flag results carry the selected multivariate `variant`.
- Flags without segment overrides report the `STATIC` reason.
- Segments are evaluated for contexts without an identity, so
  environment flags are evaluated without segments.

Fix engine type generation now that the evaluation context schema
references the evaluation result schema.

Generated with [Linear](https://linear.app/flagsmith/agent-session/389c0494-a028-440c-93fd-4dfab403905d)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@linear-code
linear-code Bot requested a review from a team as a code owner October 21, 2026 17:17
@linear-code
linear-code Bot removed the request for review from a team October 21, 2026 17:17
@linear-code
linear-code Bot requested a review from khvn26 October 21, 2026 17:17
emyller and others added 2 commits October 21, 2026 18:22
Resolve JSONPaths made of member names only, such as
`$.flags.<feature>.enabled` or `$.identity.identifier`, without a
JSONPath evaluation. Other paths are still evaluated by jsonpath-plus.

Reuse the segment matches memoised while resolving flag dependencies
when evaluating segments, so segments read through a dependency are not
evaluated twice. Memoise only once a segment condition has read a flag,
so environments without flag dependencies do not pay for it.

Generated with [Linear](https://linear.app/flagsmith/agent-session/389c0494-a028-440c-93fd-4dfab403905d)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
Add `npm run bench`, timing engine-test-data contexts and SDK offline
evaluation of environment and identity flags, with and without flag
dependencies, so the engine's performance can be compared across
revisions.

Generated with [Linear](https://linear.app/flagsmith/agent-session/389c0494-a028-440c-93fd-4dfab403905d)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f77d6583-e348-4bbb-a24a-de92446c0de9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant