Skip to content

docs: explain the swr cache option on GET server actions - #1149

Merged
vivek7405 merged 3 commits into
mainfrom
docs/swr-cache-get-actions
Jul 27, 2026
Merged

docs: explain the swr cache option on GET server actions#1149
vivek7405 merged 3 commits into
mainfrom
docs/swr-cache-get-actions

Conversation

@vivek7405

Copy link
Copy Markdown
Collaborator

Closes #1148

Documents the swr option of export const cache on GET server actions, which until now appeared only inside the inline comment { maxAge, swr, public } with no prose on any surface explaining what it does. Also names cached GET server actions in the README feature list, which previously credited only pages with HTTP Cache-Control.

What changed

  • website/app/docs/server-actions/page.ts: a new paragraph after the cached-GET example mapping the cache export onto the emitted Cache-Control header (the cache = 60 shorthand, maxAge, swr as a stale-while-revalidate grace window in seconds, public, a concrete emitted header example, and when to reach for swr).
  • website/app/docs/data-fetching/page.ts: one sentence on maxAge + swr in the verb-actions section, linking to the server-actions page for the full header reference.
  • AGENTS.md: a short swr clause inside the export const cache parenthetical of the feat: HTTP-verb server actions via config exports (GET/POST/PUT/PATCH/DELETE) [epic] #488 paragraph.
  • .agents/skills/webjs/references/data-and-actions.md: a new bullet with the full header mapping (this file is also what webjs create copies into every scaffolded app, so the scaffold surface syncs automatically, see packages/cli/lib/create.js L643).
  • README.md: the feature list now reads "HTTP Cache-Control for pages and cached GET server actions (each read carries Cache-Control plus an ETag)".

The prose matches cacheControlFor() in packages/server/src/action-config.js (L143): scope private unless public: true, max-age=<maxAge>, and stale-while-revalidate=<swr> appended only when swr > 0, GET only.

Surfaces checklist

  • Docs site: updated (two pages above). llms.txt regenerates live, no manual edit.
  • AGENTS.md + skill reference: updated.
  • README: updated.
  • Scaffold templates: N/A because the scaffold copies the repo-root skill at generate time and the gallery caching demo defers header detail to the docs site (no swr mention to sync).
  • Tests: N/A because this is a docs-only change with no behaviour change; webjs check passes on website/.
  • MCP / editor plugins / marketing page: N/A, no surface they project changed.

Test plan

  • webjs check passes on website/
  • git grep -i 'stale.while.revalidate' now hits prose on both doc pages (previously only header examples elsewhere)

The swr option of export const cache only ever appeared inside the
inline comment { maxAge, swr, public }, with no surface saying it
emits stale-while-revalidate=<n> (seconds) in Cache-Control, or when
to use it. Add the explanation next to every existing cache example
(docs site server-actions + data-fetching pages, AGENTS.md, the skill
reference) and name cached GET actions in the README feature list,
which previously only credited pages with Cache-Control.

Source of truth: cacheControlFor() in
packages/server/src/action-config.js.
@vivek7405 vivek7405 self-assigned this Jul 27, 2026
Keep 'default private' adjacent to the option list in the AGENTS.md
parenthetical, replace an ambiguous 'for up to that long' on the docs
page, and drop a parenthetical that pulled the README sentence away
from its own point (that these subsystems share one pluggable store).
The swr sentences had landed between the GET description and the
mutation one, splitting the contrast the paragraph is built around.
They belong beside the other cache sentences at the end.

@vivek7405 vivek7405 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I went over this against cacheControlFor() in packages/server/src/action-config.js and the GET response path in actions.js, and the facts hold: the number shorthand really does normalize to { maxAge: 60, swr: 0, public: false }, the scope is private unless public: true, stale-while-revalidate is appended only when swr > 0, and the weak ETag is attached to every GET-action response, so the README line about reads carrying Cache-Control plus an ETag is accurate.

What I did change was the prose. My first pass buried default private behind a long inserted clause in the AGENTS.md parenthetical, used an ambiguous "for up to that long" on the docs page, and dropped the swr sentences into the middle of the GET-versus-mutation contrast on data-fetching, which is the one structure that paragraph is built around. The README parenthetical was the worst of them: it pulled the sentence away from its own point, which is that these subsystems share one pluggable store, and the ETag has nothing to do with that. All four are fixed.

Both edited pages boot and render at 200 with the new prose in the output, and webjs check passes on website/. No behaviour change, so no test layer applies.

Comment thread README.md
WebSocket broadcast all share one pluggable store, so a single `setStore()`
call moves them onto Redis with no config files in between.
layer in the box. `cache()` for queries, HTTP Cache-Control for pages and for
cached GET server actions, a Session class with SessionStorage, NextAuth-style

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This sentence is about everything sharing one pluggable store. An ETag parenthetical here is off that point, and the extra and made the list hard to parse.

export const invalidates = (id) =&gt; ['user:' + id];
export async function updateUser(id, data) { /* ... */ }</pre>
<p>The call site never changes (<code>await getUser(7)</code>). A <strong>GET</strong> rides its args in the URL, is CSRF-exempt, and is served with <code>Cache-Control</code> + an ETag, so a repeat read within the window comes from the browser cache and a stale one revalidates with a 304. A <strong>mutation</strong> sends a body, is CSRF-protected, and on completion its <code>invalidates</code> tags evict the matching server cache and tell the client to refetch the affected reads. A wrong request method is a <code>405</code>. It is additive: an action with no <code>method</code> stays a POST, exactly as before. The cache defaults to <code>private</code>; <code>{ public: true }</code> shares the response across users keyed only by URL, so use it only for data identical for every visitor, never a per-user read.</p>
<p>The call site never changes (<code>await getUser(7)</code>). A <strong>GET</strong> rides its args in the URL, is CSRF-exempt, and is served with <code>Cache-Control</code> + an ETag, so a repeat read within the window comes from the browser cache and a stale one revalidates with a 304. A <strong>mutation</strong> sends a body, is CSRF-protected, and on completion its <code>invalidates</code> tags evict the matching server cache and tell the client to refetch the affected reads. A wrong request method is a <code>405</code>. It is additive: an action with no <code>method</code> stays a POST, exactly as before. The cache defaults to <code>private</code>; <code>{ public: true }</code> shares the response across users keyed only by URL, so use it only for data identical for every visitor, never a per-user read. In the object form <code>maxAge</code> is the freshness window in seconds and <code>swr</code> adds a stale-while-revalidate grace window (also seconds), during which an expired response is still served instantly while the browser refreshes it in the background. The full header reference lives on the <a href="/docs/server-actions">server actions</a> page.</p>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The cache detail belongs down here with the other cache sentences. Sitting between the GET and mutation descriptions, it split the contrast the paragraph is built on.

@vivek7405
vivek7405 marked this pull request as ready for review July 27, 2026 22:10
@vivek7405
vivek7405 merged commit 440dab8 into main Jul 27, 2026
19 of 20 checks passed
@vivek7405
vivek7405 deleted the docs/swr-cache-get-actions branch July 27, 2026 22:23
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.

docs: explain the swr cache option on GET actions; README omits cached GET reads

1 participant