Skip to content

feat(cache): key cache entries by configured vary headers - #4915

Merged
yusukebe merged 1 commit into
mainfrom
feat-cache-with-vary
May 16, 2026
Merged

yusukebe merged 1 commit into
mainfrom
feat-cache-with-vary

Conversation

@usualoma

@usualoma usualoma commented May 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Improves cache efficiency when the Vary header is in use.
  • Until now, options.vary only affected the response headers. With this PR, it also contributes to the cache key.
  • This is also a follow-up to the v4.12.18 vulnerability fix (568c2ec), which made Vary-bearing responses uncacheable. The change preserves that fix while letting users opt back into caching where it's safe.

Behavior changes

The behavior changes when options.vary is configured:

Situation Before After this PR
options.vary set / response has no Vary All requests share a single cache entry (requests that should return distinct responses can collide) Stored as separate variants keyed by the configured request header values
options.vary set / response Vary is a subset of options.vary Cache skipped (since v4.12.18) Stored as separate variants keyed by the configured request header values
Response Vary includes a header outside options.vary Cache skipped Cache skipped (unchanged)
Response Vary: * Cache skipped Cache skipped (unchanged)

Because of this behavior change, requests that were previously (unintentionally) sharing the same entry under options.vary are now split per header value, which can lower the hit rate. That said, this aligns with the intended semantics of Vary and should be a desirable change in virtually every deployment. On the flip side, paths that produced Vary-bearing responses — which were not cached at all after v4.12.18 — become cacheable again as long as their Vary is covered by options.vary, which raises the hit rate there.

Design note: interaction with options.keyGenerator

Users who already supply options.keyGenerator may already be folding the same request headers into the key themselves. With this change, those headers will be appended to the key a second time.

I considered skipping the options.vary-based key extension when options.keyGenerator is provided, but decided against it:

  • If a user wrote their code assuming "configuring options.vary extends the cache key", silently skipping that extension would violate their assumption.
  • A double append is a safe failure mode: it can only over-split variants — it cannot return the wrong response.

So when both are configured, options.vary still contributes to the cache key unconditionally.

The author should do the following, if applicable

  • Add tests
  • Run tests
  • bun run format:fix && bun run lint:fix to format the code
  • Add TSDoc/JSDoc to document the code

@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown

Bundle size check

main (f10dee8) #4915 (b5d97a0) +/-
Bundle Size (B) 18,489B 18,489B 0B
Bundle Size (KB) 18.06K 18.06K 0K

Compiler Diagnostics (tsc)

main (f10dee8) #4915 (b5d97a0) +/-
Files 229 229 0
Lines 146,731 146,731 0
Identifiers 125,500 125,500 0
Symbols 150,156 150,156 0
Types 160,533 160,533 0
Instantiations 413,956 413,956 0
Memory used 261,797K 261,737K -60K
I/O read 0.02s 0.03s 0.01s
I/O write 0s 0s 0s
Parse time 0.69s 0.71s 0.02s
Bind time 0.26s 0.29s 0.03s
Check time 1.45s 1.49s 0.04s
Emit time 0.01s 0.01s 0s
Total time 2.4s 2.5s 0.1s

Compiler Diagnostics (typescript-go)

main (f10dee8) #4915 (b5d97a0) +/-
Files 229 229 0
Lines 150,912 150,912 0
Identifiers 126,178 126,178 0
Symbols 190,462 190,462 0
Types 259,010 259,010 0
Instantiations 621,511 621,511 0
Memory used 163,369K 163,273K -96K
Memory allocs 1,791,372 1,791,021 -351
Config time 0.001s 0.001s 0s
BuildInfo read time 0.001s 0.001s 0s
Parse time 0.1s 0.1s 0s
Bind time 0s 0s 0s
Check time 0.417s 0.46s 0.043s
Emit time 0.005s 0.004s -0.001s
Changes compute time 0.024s 0.027s 0.003s
Total time 0.579s 0.63s 0.051s

Reported by octocov

@usualoma

usualoma commented May 8, 2026

Copy link
Copy Markdown
Member Author

Hi @yusukebe,
Would you mind reviewing this?

@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown

HTTP Performance Benchmark

Framework Runtime Average Ping Query Body
hono (origin/main) bun 41,197.66 50,828.25 40,336.49 32,428.23
hono (current) bun 42,114.31 52,158.13 40,759.41 33,425.39
Change +2.23% +2.62% +1.05% +3.07%

@codecov

codecov Bot commented May 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.01%. Comparing base (f10dee8) to head (69228f3).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4915   +/-   ##
=======================================
  Coverage   93.00%   93.01%           
=======================================
  Files         177      177           
  Lines       11999    12005    +6     
  Branches     3616     3621    +5     
=======================================
+ Hits        11160    11166    +6     
  Misses        839      839           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yusukebe yusukebe 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.

LGTM!

@yusukebe

Copy link
Copy Markdown
Member

Hey @usualoma

I considered whether there are patterns does not work, but it looks good! I'll merge this later and may include it in the next patch. Thanks!

@yusukebe
yusukebe merged commit e59db59 into main May 16, 2026
21 checks passed
@yusukebe
yusukebe deleted the feat-cache-with-vary branch May 16, 2026 09:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants