swr
Skill4 starsChanged 21 days agoMITView on GitHub
SWR v2 (stale-while-revalidate) data fetching for React and Next.js. Use when implementing or reviewing code that uses the `swr` package — useSWR hooks, cache keys, revalidation, mutations, pagination, or SWRConfig.
- Sends data out
2 other projects use a version of this.
Adopted by
Most recently taken up by
- openai/pluginstheir own version, first seen Oct 13, 2026
- Mindrally/skillstheir own version, first seen Oct 8, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- openai/plugins★ 7.8ksame name
- Mindrally/skills★ 275same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository39 other files it gives its agents.
- AGENTS.mdAGENTS.md
- authoringSkill
- chrome-devtoolsSkill
- gamificationSkill
- imagegenSkill
- improve-architectureSkill
- instructionsSkill
- monorepoSkill
- reverse-engineerSkill
- runbookSkill
- security-reviewSkill
- setup-harnessSkill
- skillsSkill
- unslopSkill
- video-reportSkill
- youtube-transcriptSkill
- code-reviewSkill
- debugSkill
- interviewSkill
- prototypeSkill
- researchSkill
- workSkill
- adsenseSkill
- astryxSkill
- cloudflare-cliSkill
- dokploy-best-practicesSkill
- extract-themeSkill
- nextjsSkill
- payload-cmsSkill
- shadersSkill
- tanstack-querySkill
- tanstack-routerSkill
- tanstack-startSkill
- tanstack-storeSkill
- tauriSkill
- vite-plusSkill
- web-assets-optimizationSkill
- web-extensionSkill
- zodSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 5 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 51
Call SWR hooks unconditionally.
- Distinctive: line 55
Keep keys stable, serializable, and specific: when filters change the result, the key changes with them.
- Very specific: line 57
Use a shared fetcher through SWRConfig when most hooks use the same transport.
- Distinctive: line 63
Prefer small reusable hooks that hide SWR details from presentation components:
- Very specific: line 105
Use isLoading for first-load UI, isValidating for background-refresh indicators over already-rendered stale data.
- Very specific: line 115
Use SWRConfig for app-wide defaults:
- Very specific: line 141
Keep revalidateOnFocus on globally unless stale data is acceptable across the product.
- Very specific: line 204
Prefer bound mutate from the related useSWR hook when changing the same resource.
- Distinctive: line 207
After create/delete operations, invalidate every affected list and detail key — a filter function key can target multiple cached resources …
- Distinctive: line 209
Keep optimistic data shape identical to the resolved data shape so no UI branch exists only during mutation.
- Distinctive: line 215
Every SWR hook has a key that includes all data-shaping inputs.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
SWR
Reference for SWR v2, the React Hooks library for stale-while-revalidate data fetching. Prefer the project's existing data layer, fetchers, and hook conventions; apply these rules on top so cache identity, revalidation, and mutation behavior stay predictable.
Branch-specific references, loaded on demand:
- pagination.md —
useSWRInfinitefor paginated and cursor-based lists. - subscriptions.md —
useSWRSubscriptionfor WebSocket and realtime sources. - nextjs.md — App Router boundaries, server prefetch, and
fallbackhydration.
First Checks
- Confirm
swris installed (package.json, lockfile) and which package manager the project uses. - Find existing fetchers, API clients, auth token handling, error types, and reusable data hooks before introducing new patterns.
- In Next.js App Router, identify the client/server boundary first — see nextjs.md.
Keys: The Key Is The Cache Identity
The SWR key is the sole identity of a cached resource. Every input that
changes the response belongs in the key: URL, query params, user scope, locale,
tenant, auth token, filters. A value read inside the fetcher but absent from
the key returns data under the wrong identity.
| Case | Pattern | Why |
| Simple resource | useSWR('/api/user', fetcher) | String key is passed to fetcher. |
| Conditional fetch | useSWR(userId ? ['/api/user', userId] : null, fetcher) | null disables the request while the hook call stays unconditional. |
| Dependent fetch | useSWR(() => user.id ? ['/api/projects', user.id] : null, fetcher) | Function keys wait for required data. |
| Auth or scope | useSWR(['/api/user', token], ([url, token]) => fetchWithToken(url, token)) | Scope-changing inputs are part of the identity. |
| Object filters | useSWR({ url: '/api/search', filters }, fetcher) | Object-like keys are serialized by SWR. |
Rules:
- Call SWR hooks unconditionally; put the condition in the key (
nullor a function key that returnsnull). - For array keys in SWR v2, the fetcher receives the full array, not spread arguments.
- Keep keys stable, serializable, and specific: when filters change the result, the key changes with them.
- Use a shared fetcher through
SWRConfigwhen most hooks use the same transport; use local fetchers for special auth, GraphQL, or non-JSON responses.
Core Pattern
Prefer small reusable hooks that hide SWR details from presentation components:
import useSWR from 'swr'
type User = {
id: string
name: string
}
const fetcher = async <T,>(url: string): Promise<T> => {
const response = await fetch(url)
if (!response.ok) {
const error = new Error('Failed to fetch data')
throw Object.assign(error, {
status: response.status,
info: await response.json().catch(() => undefined),
})
}
return response.json()
}
export function useUser(userId: string | null) {
const { data, error, isLoading, isValidating, mutate } = useSWR<User>(
userId ? `/api/users/${userId}` : null,
fetcher,
)
return {
user: data,
error,
isLoading,
isValidating,
refreshUser: mutate,
}
}- Fetchers throw on failed responses and preserve status/error details.
- Use
isLoadingfor first-load UI,isValidatingfor background-refresh indicators over already-rendered stale data. dataanderrorcan coexist after a failed revalidation: keep useful stale data visible rather than replacing it with an error screen.- Return domain names (
user,todos) from reusable hooks instead of leaking raw SWR property names; annotateuseSWR<Data, ErrorType>when the fetcher cannot infer the response type.
Global Configuration
Use SWRConfig for app-wide defaults:
import { SWRConfig } from 'swr'
export function Providers({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher: (url: string) => fetch(url).then(response => {
if (!response.ok) throw new Error('Request failed')
return response.json()
}),
revalidateOnFocus: true,
revalidateOnReconnect: true,
shouldRetryOnError: true,
}}
>
{children}
</SWRConfig>
)
}fallbacktakes a map of prefetched values keyed by SWR cache keys;fallbackDatais one hook's local initial value.- Keep
revalidateOnFocuson globally unless stale data is acceptable across the product. - Tune
dedupingInterval,refreshInterval, retry behavior, and focus throttling per endpoint cost and freshness needs. - With custom cache providers, global
mutatebroadcasts within the provider scope.
Mutations
Choose mutation APIs by intent:
| Need | API | Notes |
| Revalidate an existing resource | mutate(key) or bound mutate() | Marks the resource stale and refetches. |
| Update local cache after a known change | bound mutate(nextData) | Works well after an already-completed request. |
| Optimistic UI | mutate(asyncUpdate, { optimisticData, rollbackOnError }) | Use rollback for failed remote writes. |
| User-triggered remote write | useSWRMutation(key, mutationFetcher) | Runs only on trigger(arg). |
Optimistic update pattern:
await mutate(
async current => {
const updated = await updateTodo(todoId, { completed: true })
return current?.map(todo => (todo.id === todoId ? updated : todo))
},
{
optimisticData: current =>
current?.map(todo =>
todo.id === todoId ? { ...todo, completed: true } : todo,
),
rollbackOnError: true,
populateCache: true,
revalidate: false,
},
)Mutation fetchers receive their payload as arg — type it:
import useSWRMutation from 'swr/mutation'
type UpdateUserInput = { name: string }
async function updateUser(
url: string,
{ arg }: { arg: UpdateUserInput },
) {
const response = await fetch(url, {
method: 'PATCH',
body: JSON.stringify(arg),
})
if (!response.ok) throw new Error('Failed to update user')
return response.json()
}
const { trigger, isMutating } = useSWRMutation('/api/user', updateUser)Guidelines:
- Prefer bound
mutatefrom the relateduseSWRhook when changing the same resource; useuseSWRConfig().mutatefor cross-component invalidation, such as after logout or a global settings change. - After create/delete operations, invalidate every affected list and detail key — a filter function key can target multiple cached resources at once.
- Keep optimistic data shape identical to the resolved data shape so no UI branch exists only during mutation.
- Surface
isMutatingto disable duplicate submits.
Review Checklist
- Every SWR hook has a key that includes all data-shaping inputs.
- Conditional behavior lives in the key (
nullor function keys); every hook call is unconditional. - Fetchers throw on failed responses and preserve useful status/error details.
- First-load, background-refresh, empty, stale-with-error, and mutation states have coherent UI behavior.
- Mutations update or invalidate all affected cache keys and handle rollback.
- App Router hook usage is isolated to Client Components;
fallbackkeys match hook keys, including serialized complex keys (nextjs.md). - Pagination handles end-of-list, filter changes, loading-more state, and list item updates (pagination.md).
- Revalidation and retry settings match endpoint freshness and cost.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

