swr
$
npx mdskill add openai/plugins/swrOptimize React data fetching with SWR caching and mutations.
- Implements stale-while-revalidate for instant UI updates.
- Integrates with npm, bun, yarn, and Vercel's SWR library.
- Decides based on client-side fetching, caching, and mutation keywords.
- Generates production-ready hooks for pagination and infinite loading.
SKILL.md
.github/skills/swrView on GitHub ↗
---
name: swr
description: SWR data-fetching expert guidance. Use when building React apps with client-side data fetching, caching, revalidation, mutations, optimistic UI, pagination, or infinite loading using the SWR library.
metadata:
priority: 4
docs:
- "https://swr.vercel.app/docs"
sitemap: "https://swr.vercel.app/sitemap.xml"
pathPatterns:
- 'lib/fetcher.*'
- 'src/lib/fetcher.*'
- 'utils/fetcher.*'
- 'src/utils/fetcher.*'
- 'hooks/use*SWR*'
- 'src/hooks/use*SWR*'
- 'hooks/useFetch*'
- 'src/hooks/useFetch*'
importPatterns:
- 'swr'
- 'swr/*'
bashPatterns:
- '\bnpm\s+(install|i|add)\s+[^\n]*\bswr\b'
- '\bpnpm\s+(install|i|add)\s+[^\n]*\bswr\b'
- '\bbun\s+(install|i|add)\s+[^\n]*\bswr\b'
- '\byarn\s+add\s+[^\n]*\bswr\b'
promptSignals:
phrases:
- "swr"
- "useswr"
- "stale-while-revalidate"
allOf:
- [data fetching, client]
- [cache, revalidat]
anyOf:
- "mutation"
- "optimistic"
- "infinite loading"
- "pagination"
noneOf: []
minScore: 6
---
# SWR — React Hooks for Data Fetching
You are an expert in SWR v2 (latest: 2.4.1), the React Hooks library for data fetching by Vercel. SWR implements the stale-while-revalidate HTTP cache invalidation strategy — serve from cache first, then revalidate in the background.
## Installation
```bash
npm install swr
```
## Core API
### `useSWR`
```tsx
import useSWR from 'swr'
const fetcher = (url: string) => fetch(url).then(res => res.json())
function Profile() {
const { data, error, isLoading, mutate } = useSWR('/api/user', fetcher)
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error loading data</div>
return <div>Hello, {data.name}</div>
}
```
**Key parameters:**
- `key` — unique string, array, or function identifying the resource (often a URL)
- `fetcher` — async function that receives the key and returns data
- `options` — optional config object
**Return values:** `data`, `error`, `isLoading`, `isValidating`, `mutate`
### `useSWRMutation` — Remote Mutations
```tsx
import useSWRMutation from 'swr/mutation'
async function updateUser(url: string, { arg }: { arg: { name: string } }) {
return fetch(url, { method: 'POST', body: JSON.stringify(arg) }).then(res => res.json())
}
function Profile() {
const { trigger, isMutating } = useSWRMutation('/api/user', updateUser)
return (
<button disabled={isMutating} onClick={() => trigger({ name: 'New Name' })}>
Update
</button>
)
}
```
### `useSWRInfinite` — Pagination & Infinite Loading
```tsx
import useSWRInfinite from 'swr/infinite'
const getKey = (pageIndex: number, previousPageData: any[]) => {
if (previousPageData && !previousPageData.length) return null
return `/api/items?page=${pageIndex}`
}
function Items() {
const { data, size, setSize, isLoading } = useSWRInfinite(getKey, fetcher)
const items = data ? data.flat() : []
return (
<>
{items.map(item => <div key={item.id}>{item.name}</div>)}
<button onClick={() => setSize(size + 1)}>Load More</button>
</>
)
}
```
## Global Configuration
Wrap your app (or a subtree) with `SWRConfig` to set defaults:
```tsx
import { SWRConfig } from 'swr'
function App() {
return (
<SWRConfig value={{
fetcher: (url: string) => fetch(url).then(res => res.json()),
revalidateOnFocus: false,
dedupingInterval: 5000,
}}>
<Dashboard />
</SWRConfig>
)
}
```
## Revalidation Strategies
| Strategy | Option | Default |
|---|---|---|
| On window focus | `revalidateOnFocus` | `true` |
| On network recovery | `revalidateOnReconnect` | `true` |
| On mount if stale | `revalidateIfStale` | `true` |
| Polling | `refreshInterval` | `0` (disabled) |
| Manual | Call `mutate()` | — |
## Optimistic Updates
```tsx
const { trigger } = useSWRMutation('/api/user', updateUser, {
optimisticData: (current) => ({ ...current, name: 'New Name' }),
rollbackOnError: true,
populateCache: true,
revalidate: false,
})
```
## Conditional Fetching
Pass `null` or a falsy key to skip fetching:
```tsx
const { data } = useSWR(userId ? `/api/user/${userId}` : null, fetcher)
```
## Error Retry
SWR retries on error by default with exponential backoff. Customize with:
```tsx
useSWR(key, fetcher, {
onErrorRetry: (error, key, config, revalidate, { retryCount }) => {
if (error.status === 404) return // Don't retry on 404
if (retryCount >= 3) return // Max 3 retries
setTimeout(() => revalidate({ retryCount }), 5000)
},
})
```
## `useSWRSubscription` — Real-Time Data Sources
Subscribe to real-time data (WebSockets, SSE, etc.) with automatic deduplication:
```tsx
import useSWRSubscription from 'swr/subscription'
function LivePrice({ symbol }: { symbol: string }) {
const { data } = useSWRSubscription(
`wss://stream.example.com/${symbol}`,
(key, { next }) => {
const ws = new WebSocket(key)
ws.onmessage = (event) => next(null, JSON.parse(event.data))
ws.onerror = (event) => next(event)
return () => ws.close()
}
)
return <span>{data?.price}</span>
}
```
The `subscribe` function receives a `next(error, data)` callback and must return a cleanup function. Multiple components using the same key share a single subscription.
## Key Rules
- **Keys must be unique** — two `useSWR` calls with the same key share cache and deduplicate requests
- **Fetcher is optional** when set via `SWRConfig`
- **`mutate(key)`** globally revalidates any hook matching that key
- **Array keys** like `useSWR(['/api/user', id], fetcher)` — the fetcher receives the full array
- **Never call hooks conditionally** — use conditional keys (`null`) instead
More from openai/plugins
- accessibility-and-inclusive-visualizationMake data visualizations accessible and inclusive. Use when the user needs chart or diagram accessibility guidance, text alternatives for complex visuals, color and contrast review, keyboard support, reduced-motion behavior for animation or parallax, or an accessibility QA workflow for exported figures, UML-like diagrams, and dashboards.
- agent-browserBrowser automation CLI for AI agents. Use when the user needs to interact with websites, verify dev server output, test web apps, navigate pages, fill forms, click buttons, take screenshots, extract data, or automate any browser task. Also triggers when a dev server starts so you can verify it visually.
- agent-browser-verifyAutomated browser verification for dev servers. Triggers when a dev server starts to run a visual gut-check with agent-browser — verifies the page loads, checks for console errors, validates key UI elements, and reports pass/fail before continuing.
- agents-sdkBuild AI agents on Cloudflare Workers using the Agents SDK. Load when creating stateful agents, durable workflows, real-time WebSocket apps, scheduled tasks, MCP servers, or chat applications. Covers Agent class, state management, callable RPC, Workflows integration, and React hooks. Biases towards retrieval from Cloudflare docs over pre-trained knowledge.
- ai-elementsAI Elements component library guidance — pre-built React components for AI interfaces built on shadcn/ui. Use when building chat UIs, message displays, tool call rendering, streaming responses, reasoning panels, or any AI-native interface with the AI SDK.
- ai-gatewayVercel AI Gateway expert guidance. Use when configuring model routing, provider failover, cost tracking, or managing multiple AI providers through a unified API.
- ai-generation-persistenceAI generation persistence patterns — unique IDs, addressable URLs, database storage, and cost tracking for every LLM generation
- ai-sdkVercel AI SDK expert guidance. Use when building AI-powered features — chat interfaces, text generation, structured output, tool calling, agents, MCP integration, streaming, embeddings, reranking, image generation, or working with any LLM provider.
- aiq-deploy|
- aiq-research|