Skip to content

perf: optimize selection-set serializer hot path + fix extensions.http leak#4403

Draft
Copilot wants to merge 10 commits into
mainfrom
copilot/optimize-execution-result-serialization
Draft

perf: optimize selection-set serializer hot path + fix extensions.http leak#4403
Copilot wants to merge 10 commits into
mainfrom
copilot/optimize-execution-result-serialization

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

Benchmark comparison showed the selection-set serialization branch running ~5-6% slower than main (360µs vs 348µs avg; 332k vs 351k iterations/2.5min). Also identified a correctness bug where the internal extensions.http field was leaking to clients through the new fast path.

Correctness

Strip extensions.http in stringifyWithDocument — the fast path bypassed omitInternalsFromResultErrors, so Yoga's internal HTTP status hints (extensions.http) were included in the serialized response. Now uses a shared RESULT_EXTENSIONS_OPTIONS with ignoredFields to strip internal fields, and skips the "extensions" key entirely when only internal fields are present (avoids emitting "extensions":{}).

Performance

commaEscapedKey — pre-compute ',' + escapedKey at plan compile time. The hot loop now uses field.commaEscapedKey for non-first fields, eliminating one string concatenation per non-first field (~240 ops saved per benchmark request).

isSimple flag on ProjectionPlanField — pre-computed as typeGuard === null && !hasSkip && !hasInclude && !isTypename. When true, the serializer skips four branch checks per field and jumps directly to value serialization. For the benchmark query where every field is simple, this eliminates 4 × 260 = 1,040 branches per request.

hasConditionalFields on CompiledProjectionPlan — recursively pre-computed at plan compile time. getVariableValues is now gated on plan.hasConditionalFields && plan.variableDefinitions.length > 0. Queries that declare variables but use no @skip/@include (e.g. pagination) skip coercion entirely.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@codesandbox
Copy link
Copy Markdown

codesandbox Bot commented Mar 19, 2026

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@theguild-bot
Copy link
Copy Markdown
Collaborator

theguild-bot commented Mar 19, 2026

Apollo Federation Subgraph Compatibility Results

Federation 1 Support Federation 2 Support
_service🟢
@key (single)🟢
@key (multi)🟢
@key (composite)🟢
repeatable @key🟢
@requires🟢
@provides🟢
federated tracing🟢
@link🟢
@shareable🟢
@tag🟢
@override🟢
@inaccessible🟢
@composeDirective🟢
@interfaceObject🟢

Learn more:

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://670b87e1.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

theguild-bot commented Mar 19, 2026

✅ Yoga Benchmark Results

     ✓ no_errors{mode:graphql}
     ✓ expected_result{mode:graphql}
     ✓ no_errors{mode:graphql-jit}
     ✓ expected_result{mode:graphql-jit}
     ✓ no_errors{mode:graphql-response-cache}
     ✓ expected_result{mode:graphql-response-cache}
     ✓ no_errors{mode:graphql-no-parse-validate-cache}
     ✓ expected_result{mode:graphql-no-parse-validate-cache}
     ✓ no_errors{mode:uws}
     ✓ expected_result{mode:uws}

     checks.......................................: 100.00% ✓ 694248      ✗ 0     
     data_received................................: 2.8 GB  19 MB/s
     data_sent....................................: 118 MB  786 kB/s
     http_req_blocked.............................: avg=1.58µs   min=932ns    med=1.39µs   max=1.17ms   p(90)=1.99µs   p(95)=2.19µs  
     http_req_connecting..........................: avg=2ns      min=0s       med=0s       max=158.54µs p(90)=0s       p(95)=0s      
     http_req_duration............................: avg=343.33µs min=207.74µs med=321.96µs max=25.64ms  p(90)=465.14µs p(95)=485.22µs
       { expected_response:true }.................: avg=343.33µs min=207.74µs med=321.96µs max=25.64ms  p(90)=465.14µs p(95)=485.22µs
     ✓ { mode:graphql-jit }.......................: avg=264.36µs min=207.74µs med=256.04µs max=24.39ms  p(90)=284.92µs p(95)=296.82µs
     ✓ { mode:graphql-no-parse-validate-cache }...: avg=490.32µs min=416.69µs med=470.59µs max=25.64ms  p(90)=507.6µs  p(95)=531.98µs
     ✓ { mode:graphql-response-cache }............: avg=329.53µs min=263.01µs med=321.57µs max=10.18ms  p(90)=353.39µs p(95)=366.69µs
     ✓ { mode:graphql }...........................: avg=350.78µs min=277.9µs  med=332.22µs max=16.19ms  p(90)=376.64µs p(95)=428.23µs
     ✓ { mode:uws }...............................: avg=337.96µs min=270.54µs med=324.06µs max=20.75ms  p(90)=354.17µs p(95)=367.59µs
     http_req_failed..............................: 0.00%   ✓ 0           ✗ 347124
     http_req_receiving...........................: avg=33.02µs  min=17.42µs  med=32.31µs  max=2.96ms   p(90)=39.43µs  p(95)=42.56µs 
     http_req_sending.............................: avg=10.21µs  min=5.74µs   med=9.95µs   max=1.09ms   p(90)=13.95µs  p(95)=16.48µs 
     http_req_tls_handshaking.....................: avg=0s       min=0s       med=0s       max=0s       p(90)=0s       p(95)=0s      
     http_req_waiting.............................: avg=300.09µs min=172.23µs med=279.6µs  max=25.37ms  p(90)=421.62µs p(95)=440.23µs
     http_reqs....................................: 347124  2314.129565/s
     iteration_duration...........................: avg=426.92µs min=272.22µs med=404.07µs max=25.81ms  p(90)=549.75µs p(95)=572.91µs
     iterations...................................: 347124  2314.129565/s
     vus..........................................: 1       min=1         max=2   
     vus_max......................................: 2       min=2         max=2   

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://4e59fee2.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://4b84e5e6.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://5a9d897e.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://1479a867.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

Copilot AI and others added 9 commits March 21, 2026 18:16
…ults

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
…e unused QUOTE import)

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
…gnore

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
…serialization

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
- Fast-path stringifyString: scan for special chars, skip JSON.stringify for plain strings
- Add scalarHint to ProjectionPlanField for type-specific leaf serialization (String/Int/Float/Boolean/ID)
- Pre-compute hasSkip/hasInclude booleans on each plan field to avoid .length > 0 checks in hot loop
- Lazy __typename lookup in projectObject: only pay for property access when type guards or __typename output exists
- projectEnumValue: use direct quote-wrapping for validated enum identifiers (no JSON.stringify needed)

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
…ey fragments, use indexed loops

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
…ethods

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://7afc0398.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

…ization + fix extensions.http leak

Co-authored-by: ardatan <20847995+ardatan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/graphql-hive/graphql-yoga/sessions/cabef9b6-6cba-4aea-a8ac-033860eac2c7
Copilot AI changed the title feat: use selection-set-based serialization for GraphQL execution results perf: optimize selection-set serializer hot path + fix extensions.http leak Mar 21, 2026
@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://8f5d0508.envelop.pages.dev

@theguild-bot
Copy link
Copy Markdown
Collaborator

💻 Website Preview

The latest changes are available as preview in: https://pr-4403.graphql-yoga.pages.dev

Sign up for free to 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.

3 participants