Skip to content

feat(cache): add allowQuery option to filter query params in cache key#4078

Open
fmoessle wants to merge 3 commits intonitrojs:mainfrom
fmoessle:feat/cache-allow-query
Open

feat(cache): add allowQuery option to filter query params in cache key#4078
fmoessle wants to merge 3 commits intonitrojs:mainfrom
fmoessle:feat/cache-allow-query

Conversation

@fmoessle
Copy link
Contributor

@fmoessle fmoessle commented Mar 6, 2026

Summary

  • Adds allowQuery option to defineCachedHandler and route rules cache config
  • When set, only the listed query parameter names are included in the cache key
  • If set to an empty array [], all query parameters are ignored (only pathname is used)
  • If undefined (default), all query parameters are included — no behavior change
  • Useful for ignoring tracking params like utm_source, fbclid, etc.

Closes nuxt/nuxt#33728

Test plan

  • Added test fixture api/cached-allow-query.ts with allowQuery: ["q"]
  • Added route rule /rules/allow-query/** with allowQuery: ["q"]
  • Added test: same q param with different unlisted params hits cache
  • Added test: different q param gets different cache entry
  • Tests pass on multiple presets (node, cloudflare-pages, cloudflare-module, etc.)
  • Updated cache docs with allowQuery field

🤖 Generated with Claude Code

Allow users to specify which query parameters should be included in the cache key
via `allowQuery` option on `defineCachedHandler` and route rules cache config.

- `undefined`: all query params included (default, no behavior change)
- `[]`: all query params ignored (only pathname used)
- `["q"]`: only listed params included

Closes nuxt/nuxt#33728

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@fmoessle fmoessle requested a review from pi0 as a code owner March 6, 2026 18:45
@vercel
Copy link

vercel bot commented Mar 6, 2026

@fmoessle is attempting to deploy a commit to the Nitro Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

📝 Walkthrough

Walkthrough

Adds an allowQuery option to cache configuration and implements selective query-parameter inclusion in cache key generation; updates types, runtime cache logic, docs, fixtures, Vercel preset snapshots, and tests to exercise the new behavior.

Changes

Cohort / File(s) Summary
Type Definitions
src/types/runtime/cache.ts
Add `allowQuery?: string[]
Cache Implementation
src/runtime/internal/cache.ts
Modify auto-generated cache key: when allowQuery is provided include only those query params; undefined keeps existing behavior; empty array ignores all query params.
Documentation
docs/1.docs/7.cache.md
Document allowQuery semantics: undefined = include all query params, [] = ignore all, array = include only listed names.
Test Fixtures & Route
test/fixture/nitro.config.ts, test/fixture/server/routes/api/cached-allow-query.ts
Add route rule and cached handler configured with allowQuery: ["q"], swr: true, and maxAge: 60.
Tests
test/tests.ts
Add test verifying unlisted query params are ignored in cache keys while listed params separate cache entries.
Vercel Preset Snapshots
test/presets/vercel.test.ts
Add ISR/route and function entries for the allow-query route and update snapshots/prerender config references.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows conventional commits format with 'feat(cache):' prefix and clearly describes the main change of adding allowQuery option.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, explaining the feature, test plan, and linked issue.
Linked Issues check ✅ Passed The PR implements all coding requirements from linked issue #33728: adds allowQuery option to cache configuration and defineCachedHandler, handles both specified and empty array cases correctly, and preserves original URL while affecting only cache key generation.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the allowQuery feature: documentation updates, type definitions, cache key logic, test fixtures, route rules, and comprehensive test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Route rules config passes `allowQuery` as `readonly string[]`, so the
type needs to accept both mutable and readonly arrays (matching `varies`).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/types/runtime/cache.ts (1)

41-47: Accept readonly arrays for allowQuery.

This option is only read, and varies already accepts readonly arrays. Keeping allowQuery as string[] needlessly rejects common as const / shared config values in route rules and defineCachedHandler.

♻️ Proposed type tweak
-  allowQuery?: string[];
+  allowQuery?: string[] | readonly string[];

As per coding guidelines, "Update types and JSDoc for API changes".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/types/runtime/cache.ts` around lines 41 - 47, Change the allowQuery
option type from mutable array to an immutable/readonly array type so callers
can pass `as const` and shared configs; specifically update the declaration for
allowQuery to use `readonly string[]` (or `ReadonlyArray<string>`) instead of
`string[]`, and update the JSDoc sentence to state that readonly arrays are
accepted; ensure this matches the existing `varies` usage (which already accepts
readonly arrays) so downstream callers like route rules and
`defineCachedHandler` accept `as const` values.
test/tests.ts (1)

696-715: Add a route-rule coverage case too.

This only exercises allowQuery on defineCachedHandler via /api/cached-allow-query. The new routeRules.cache.allowQuery path added in test/fixture/nitro.config.ts is still untested, so a regression in the route-rule plumbing could slip through.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/tests.ts` around lines 696 - 715, Add a parallel test that exercises the
route configured via routeRules.cache.allowQuery in the fixture (the route
defined in test/fixture/nitro.config.ts) using the same callHandler pattern as
the existing defineCachedHandler test: call the route twice with the same listed
query param and differing unlisted params to assert the timestamps are
identical, then call with a different listed query param to assert a different
timestamp; use the same skip condition (it.skipIf(...)) and mirror the
assertions used for /api/cached-allow-query so route-rule plumbing is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/runtime/internal/cache.ts`:
- Around line 205-213: The cache key builder currently collapses repeated query
values because it uses event.url.searchParams.get() and params.set(), so e.g.
?tag=a&tag=b and ?tag=a become identical; change the logic in the block that
references opts.allowQuery and event.url.searchParams to retrieve all values for
each allowed key (use getAll or iterate searchParams entries for that key) and
append each value to the local URLSearchParams (use params.append) so duplicate
values and their order are preserved when computing the search string assigned
to the search variable.

---

Nitpick comments:
In `@src/types/runtime/cache.ts`:
- Around line 41-47: Change the allowQuery option type from mutable array to an
immutable/readonly array type so callers can pass `as const` and shared configs;
specifically update the declaration for allowQuery to use `readonly string[]`
(or `ReadonlyArray<string>`) instead of `string[]`, and update the JSDoc
sentence to state that readonly arrays are accepted; ensure this matches the
existing `varies` usage (which already accepts readonly arrays) so downstream
callers like route rules and `defineCachedHandler` accept `as const` values.

In `@test/tests.ts`:
- Around line 696-715: Add a parallel test that exercises the route configured
via routeRules.cache.allowQuery in the fixture (the route defined in
test/fixture/nitro.config.ts) using the same callHandler pattern as the existing
defineCachedHandler test: call the route twice with the same listed query param
and differing unlisted params to assert the timestamps are identical, then call
with a different listed query param to assert a different timestamp; use the
same skip condition (it.skipIf(...)) and mirror the assertions used for
/api/cached-allow-query so route-rule plumbing is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 83f13b78-1432-4fc3-9dd2-ad6166aa0928

📥 Commits

Reviewing files that changed from the base of the PR and between bfbb207 and 61e4c3f.

📒 Files selected for processing (6)
  • docs/1.docs/7.cache.md
  • src/runtime/internal/cache.ts
  • src/types/runtime/cache.ts
  • test/fixture/nitro.config.ts
  • test/fixture/server/routes/api/cached-allow-query.ts
  • test/tests.ts

Comment on lines +205 to +213
if (opts.allowQuery) {
const params = new URLSearchParams();
for (const key of opts.allowQuery) {
const value = event.url.searchParams.get(key);
if (value !== null) {
params.set(key, value);
}
}
const search = params.size > 0 ? `?${params.toString()}` : "";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Preserve repeated allowed query values in the cache key.

Line 208 only reads the first value with searchParams.get(), so ?tag=a&tag=b and ?tag=a collapse to the same cache entry when tag is allowed. That can serve the wrong cached response for multi-value filters.

🐛 Proposed fix
         const params = new URLSearchParams();
         for (const key of opts.allowQuery) {
-          const value = event.url.searchParams.get(key);
-          if (value !== null) {
-            params.set(key, value);
+          for (const value of event.url.searchParams.getAll(key)) {
+            params.append(key, value);
           }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (opts.allowQuery) {
const params = new URLSearchParams();
for (const key of opts.allowQuery) {
const value = event.url.searchParams.get(key);
if (value !== null) {
params.set(key, value);
}
}
const search = params.size > 0 ? `?${params.toString()}` : "";
if (opts.allowQuery) {
const params = new URLSearchParams();
for (const key of opts.allowQuery) {
for (const value of event.url.searchParams.getAll(key)) {
params.append(key, value);
}
}
const search = params.size > 0 ? `?${params.toString()}` : "";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/runtime/internal/cache.ts` around lines 205 - 213, The cache key builder
currently collapses repeated query values because it uses
event.url.searchParams.get() and params.set(), so e.g. ?tag=a&tag=b and ?tag=a
become identical; change the logic in the block that references opts.allowQuery
and event.url.searchParams to retrieve all values for each allowed key (use
getAll or iterate searchParams entries for that key) and append each value to
the local URLSearchParams (use params.append) so duplicate values and their
order are preserved when computing the search string assigned to the search
variable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/types/runtime/cache.ts`:
- Around line 41-47: The JSDoc for the allowQuery field is inaccurate: the cache
key currently uses event.url.searchParams.get(key) which only reads the first
value for repeated query parameters, so repeated params (e.g., q=a&q=b) will
collide with single occurrences; update the allowQuery JSDoc comment (for the
allowQuery property) to explicitly state "only the first occurrence/value of
each allowed query parameter is used when building the cache key" OR change the
implementation that builds the cache key to use all occurrences (e.g.,
searchParams.getAll or iterate entries) so every value contributes to the key —
reference allowQuery and the code path using event.url.searchParams.get(key) to
locate where to update either the docs or the key-construction logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a5f135e-4ef4-4662-a495-af4a413fc4e0

📥 Commits

Reviewing files that changed from the base of the PR and between 61e4c3f and c0fd5d5.

📒 Files selected for processing (1)
  • src/types/runtime/cache.ts

Comment on lines +41 to +47
/**
* List of query string parameter names that will be considered for caching.
* - If undefined, all query parameters are included in the cache key.
* - If an empty array `[]`, all query parameters are ignored (only pathname is used for caching).
* - If a list of parameter names, only those parameters are included in the cache key.
*/
allowQuery?: string[] | readonly string[];
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how `allowQuery` values are incorporated into the cache key.
# Expected result: the implementation uses `searchParams.get(key)`,
# which confirms only one value per query name is considered.

sed -n '201,216p' src/runtime/internal/cache.ts

Repository: nitrojs/nitro

Length of output: 607


JSDoc must clarify that only the first value per query parameter is used in the cache key.

The implementation uses event.url.searchParams.get(key), which reads only the first value when a query parameter appears multiple times. Requests like /foo?q=a&q=b and /foo?q=a will collide when allowQuery: ["q"] because both produce the same cache key. Update the JSDoc on lines 43-44 to explicitly state that only the first occurrence of each allowed parameter contributes to the key, or modify the implementation to include all occurrences. Per coding guidelines, JSDoc must accurately reflect API behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/types/runtime/cache.ts` around lines 41 - 47, The JSDoc for the
allowQuery field is inaccurate: the cache key currently uses
event.url.searchParams.get(key) which only reads the first value for repeated
query parameters, so repeated params (e.g., q=a&q=b) will collide with single
occurrences; update the allowQuery JSDoc comment (for the allowQuery property)
to explicitly state "only the first occurrence/value of each allowed query
parameter is used when building the cache key" OR change the implementation that
builds the cache key to use all occurrences (e.g., searchParams.getAll or
iterate entries) so every value contributes to the key — reference allowQuery
and the code path using event.url.searchParams.get(key) to locate where to
update either the docs or the key-construction logic.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 6, 2026

Open in StackBlitz

npm i https://pkg.pr.new/nitro@4078

commit: a35aae8

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/presets/vercel.test.ts`:
- Around line 472-473: Update the test in test/presets/vercel.test.ts so it
asserts the actual JSON contents for the new allow-query prerender config
instead of (or in addition to) the existing isr path: locate the assertion that
reads the file 'functions/rules/isr/[...]-isr.prerender-config.json' and change
it to read and assert the contents of
'functions/rules/allow-query/[...]-isr.prerender-config.json' (or add a second
assertion that reads that allow-query path and matches its expected
snapshot/JSON), ensuring the test verifies the serialized allowQuery field is
present; reference the file-reading/assertion block in vercel.test.ts when
making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dbf2e45b-bebd-4353-a12d-bf5e9ae4686d

📥 Commits

Reviewing files that changed from the base of the PR and between c0fd5d5 and 3e54b26.

📒 Files selected for processing (1)
  • test/presets/vercel.test.ts

Comment on lines +472 to +473
"functions/rules/allow-query/[...]-isr.func (symlink)",
"functions/rules/allow-query/[...]-isr.prerender-config.json",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Assert the new allow-query prerender config contents.

This snapshot only proves the file exists. The actual content check still reads functions/rules/isr/[...]-isr.prerender-config.json, so a regression where /rules/allow-query/** stops serializing allowQuery would slip through. Please point that assertion at functions/rules/allow-query/[...]-isr.prerender-config.json or add a second assertion for it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/presets/vercel.test.ts` around lines 472 - 473, Update the test in
test/presets/vercel.test.ts so it asserts the actual JSON contents for the new
allow-query prerender config instead of (or in addition to) the existing isr
path: locate the assertion that reads the file
'functions/rules/isr/[...]-isr.prerender-config.json' and change it to read and
assert the contents of
'functions/rules/allow-query/[...]-isr.prerender-config.json' (or add a second
assertion that reads that allow-query path and matches its expected
snapshot/JSON), ensuring the test verifies the serialized allowQuery field is
present; reference the file-reading/assertion block in vercel.test.ts when
making the change.

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.

Ignore specific Query Parameters in routeRules cache configuration

1 participant