/web-data-fetching-swr
SWR data fetching patterns - useSWR, useSWRMutation, caching, revalidation, infinite scroll
$ npx -y skills add agents-inc/skills --skill web-data-fetching-swr --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/web-data-fetching-swr
Context preview
The summary Claude sees to decide when to auto-load this skill.
SWR data fetching patterns - useSWR, useSWRMutation, caching, revalidation, infinite scroll
SKILL.md
web-data-fetching-swr.SKILL.mdname: web-data-fetching-swr
description: SWR data fetching patterns - useSWR, useSWRMutation, caching, revalidation, infinite scroll
SWR Data Fetching Patterns
> **Quick Guide:** SWR implements the stale-while-revalidate caching strategy: show cached data instantly, revalidate in the background. Keys must be stable (strings or stable arrays), `isLoading` is for initial fetches only (use `isValidating` for background refreshes), and all write operations go through `useSWRMutation`. The null key pattern is how you do conditional fetching -- never call hooks conditionally.
---
<critical_requirements>
CRITICAL: Before Using This Skill
**(You MUST use a stable key -- keys should NOT change on every render or you'll trigger infinite requests)**
**(You MUST handle isLoading vs isValidating correctly -- isLoading is true only on initial fetch with no data)**
**(You MUST wrap mutations in `useSWRMutation` for write operations -- NOT useSWR)**
**(You MUST use named constants for ALL timeout, retry, and interval values -- NO magic numbers)**
**(You MUST use named exports only -- NO default exports)**
</critical_requirements>
---
**Auto-detection:** SWR, useSWR, useSWRMutation, useSWRInfinite, useSWRImmutable, SWRConfig, mutate, revalidate, fetcher, stale-while-revalidate, preload
**When to use:**
- Read-heavy applications with infrequent mutations
- Need lightweight bundle (~5KB gzipped)
- Simple caching with automatic revalidation
- Applications where stale-while-revalidate pattern is desired
**When NOT to use:**
- Complex mutation workflows requiring many lifecycle callbacks
- Need built-in request cancellation (SWR requires manual AbortController)
- Complex dependent queries needing fine-grained invalidation control
**Key patterns covered:**
- useSWR hook with typed fetchers and state handling
- isLoading vs isValidating distinction (the most common mistake)
- Revalidation strategies (focus, reconnect, interval, manual)
- useSWRMutation for write operations with optimistic updates
- useSWRInfinite for cursor and offset pagination
- Null key pattern for conditional fetching
- SWRConfig for global defaults and SSR fallback
**Detailed Resources:**
- [examples/core.md](examples/core.md) -- Fetchers, return values, SWRConfig, key patterns
- [examples/mutations.md](examples/mutations.md) -- useSWRMutation, optimistic updates, cache invalidation
- [examples/caching.md](examples/caching.md) -- Revalidation strategies, prefetching, persistence
- [examples/pagination.md](examples/pagination.md) -- useSWRInfinite, infinite scroll, offset pagination
- [examples/conditional.md](examples/conditional.md) -- Dependent queries, auth-gated fetching
- [examples/error-handling.md](examples/error-handling.md) -- Retry config, error boundaries, network detection
- [examples/suspense.md](examples/suspense.md) -- Suspense integration, SSR fallback patterns
- [reference.md](reference.md) -- Decision frameworks, configuration tables
---
<philosophy>
Philosophy
SWR (stale-while-revalidate) returns cached data first, then revalidates in the background. This creates fast, responsive UIs while ensuring data freshness.
**Core principles:**
- **Stale-While-Revalidate**: Show cached data immediately, update in background
- **Deduplication**: Multiple components using same key share one request
- **Focus Revalidation**: Refetch when user returns to tab
- **Optimistic UI**: Update UI immediately, rollback on error
- **Minimal API**: Simple hooks, less configuration than alternatives
**Trade-offs:**
- Simpler API means less control over complex mutation scenarios
- Request cancellation requires manual AbortController setup
- Less opinionated about mutations (fewer lifecycle callbacks)
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Typed Fetcher
The fetcher must throw on non-OK responses. If it doesn't throw, SWR treats error bodies as valid data.
// lib/fetcher.ts
interface FetchError extends Error {
info: unknown;
status: number;
}
const fetcher = async <T>(url: string): Promise<T> => {
const response = await fetch(url);
if (!response.ok) {
const error = new Error("Fetch failed") as FetchError;
error.info = await response.json().catch(() => null);
error.status = response.status;
throw error;
}
return response.json();
};
export { fetcher };
export type { FetchError };**Why good:** Throws on error (required for SWR error state to work), attaches status for conditional handling, typed error enables downstream type narrowing
See [examples/core.md](examples/core.md) for axios, GraphQL, and multi-argument fetcher variants.
---
Pattern 2: isLoading vs isValidating
The most common SWR mistake. `isLoading` is true only on initial fetch with no data. `isValidating` is true during any in-flight request.
// State combinations:
// Initial load: { data: undefined, isLoading: true, isValidating: true }
// Success: { data: T, isLoading: false, isValidating: false }
// Revalidating: { data: T, isLoading: false, isValidating: true }
// Error (no data): { error: Error, isLoading: false, isValidating: false }
// Error (has data): { data: T, error: Error, isLoading: false }// BAD: Using isValidating as loading indicator hides cached data
if (isValidating) return <Spinner />;
// GOOD: isLoading for initial, isValidating for refresh indicator
if (isLoading) return <Spinner />;
return (
<div>
{isValidating && <RefreshIndicator />}
{error && data && <Banner>Data may be outdated</Banner>}
<Content data={data} />
</div>
);**Why bad:** Showing spinner during background revalidation hides perfectly valid cached data, defeating the purpose of stale-while-revalidate
See [examples/core.md](examples/core.md) for full state handling with error + stale data combinations.
---
Pattern 3: SWRConfig Global Defaults
Centralize fetcher, retry, an
Read more
name: web-data-fetching-swr description: SWR data fetching patterns - useSWR, useSWRMutation, caching, revalidation, infinite scroll
SWR Data Fetching Patterns
> **Quick Guide:** SWR implements the stale-while-revalidate caching strategy: show cached data instantly, revalidate in the background. Keys must be stable (strings or stable arrays), `isLoading` is for initial fetches only (use `isValidating` for background refreshes), and all write operations go through `useSWRMutation`. The null key pattern is how you do conditional fetching -- never call hooks conditionally.
---
<critical_requirements>
CRITICAL: Before Using This Skill
**(You MUST use a stable key -- keys should NOT change on every render or you'll trigger infinite requests)**
**(You MUST handle isLoading vs isValidating correctly -- isLoading is true only on initial fetch with no data)**
**(You MUST wrap mutations in `useSWRMutation` for write operations -- NOT useSWR)**
**(You MUST use named constants for ALL timeout, retry, and interval values -- NO magic numbers)**
**(You MUST use named exports only -- NO default exports)**
</critical_requirements>
---
**Auto-detection:** SWR, useSWR, useSWRMutation, useSWRInfinite, useSWRImmutable, SWRConfig, mutate, revalidate, fetcher, stale-while-revalidate, preload
**When to use:**
- Read-heavy applications with infrequent mutations
- Need lightweight bundle (~5KB gzipped)
- Simple caching with automatic revalidation
- Applications where stale-while-revalidate pattern is desired
**When NOT to use:**
- Complex mutation workflows requiring many lifecycle callbacks
- Need built-in request cancellation (SWR requires manual AbortController)
- Complex dependent queries needing fine-grained invalidation control
**Key patterns covered:**
- useSWR hook with typed fetchers and state handling
- isLoading vs isValidating distinction (the most common mistake)
- Revalidation strategies (focus, reconnect, interval, manual)
- useSWRMutation for write operations with optimistic updates
- useSWRInfinite for cursor and offset pagination
- Null key pattern for conditional fetching
- SWRConfig for global defaults and SSR fallback
**Detailed Resources:**
- [examples/core.md](examples/core.md) -- Fetchers, return values, SWRConfig, key patterns
- [examples/mutations.md](examples/mutations.md) -- useSWRMutation, optimistic updates, cache invalidation
- [examples/caching.md](examples/caching.md) -- Revalidation strategies, prefetching, persistence
- [examples/pagination.md](examples/pagination.md) -- useSWRInfinite, infinite scroll, offset pagination
- [examples/conditional.md](examples/conditional.md) -- Dependent queries, auth-gated fetching
- [examples/error-handling.md](examples/error-handling.md) -- Retry config, error boundaries, network detection
- [examples/suspense.md](examples/suspense.md) -- Suspense integration, SSR fallback patterns
- [reference.md](reference.md) -- Decision frameworks, configuration tables
---
<philosophy>
Philosophy
SWR (stale-while-revalidate) returns cached data first, then revalidates in the background. This creates fast, responsive UIs while ensuring data freshness.
**Core principles:**
- **Stale-While-Revalidate**: Show cached data immediately, update in background
- **Deduplication**: Multiple components using same key share one request
- **Focus Revalidation**: Refetch when user returns to tab
- **Optimistic UI**: Update UI immediately, rollback on error
- **Minimal API**: Simple hooks, less configuration than alternatives
**Trade-offs:**
- Simpler API means less control over complex mutation scenarios
- Request cancellation requires manual AbortController setup
- Less opinionated about mutations (fewer lifecycle callbacks)
</philosophy>
---
<patterns>
Core Patterns
Pattern 1: Typed Fetcher
The fetcher must throw on non-OK responses. If it doesn't throw, SWR treats error bodies as valid data.
// lib/fetcher.ts
interface FetchError extends Error {
info: unknown;
status: number;
}
const fetcher = async <T>(url: string): Promise<T> => {
const response = await fetch(url);
if (!response.ok) {
const error = new Error("Fetch failed") as FetchError;
error.info = await response.json().catch(() => null);
error.status = response.status;
throw error;
}
return response.json();
};
export { fetcher };
export type { FetchError };**Why good:** Throws on error (required for SWR error state to work), attaches status for conditional handling, typed error enables downstream type narrowing
See [examples/core.md](examples/core.md) for axios, GraphQL, and multi-argument fetcher variants.
---
Pattern 2: isLoading vs isValidating
The most common SWR mistake. `isLoading` is true only on initial fetch with no data. `isValidating` is true during any in-flight request.
// State combinations:
// Initial load: { data: undefined, isLoading: true, isValidating: true }
// Success: { data: T, isLoading: false, isValidating: false }
// Revalidating: { data: T, isLoading: false, isValidating: true }
// Error (no data): { error: Error, isLoading: false, isValidating: false }
// Error (has data): { data: T, error: Error, isLoading: false }// BAD: Using isValidating as loading indicator hides cached data
if (isValidating) return <Spinner />;
// GOOD: isLoading for initial, isValidating for refresh indicator
if (isLoading) return <Spinner />;
return (
<div>
{isValidating && <RefreshIndicator />}
{error && data && <Banner>Data may be outdated</Banner>}
<Content data={data} />
</div>
);**Why bad:** Showing spinner during background revalidation hides perfectly valid cached data, defeating the purpose of stale-while-revalidate
See [examples/core.md](examples/core.md) for full state handling with error + stale data combinations.
---
Pattern 3: SWRConfig Global Defaults
Centralize fetcher, retry, an
Showing the first part of this file.
The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Other skills on agents-inc-skills.
- /ai-infrastructure-huggingface-inference
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints
Open skill - /ai-infrastructure-litellm
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment
Open skill - /ai-infrastructure-modal
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Open skill - /ai-infrastructure-ollama
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint
Open skill - /ai-infrastructure-replicate
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Open skill - /ai-infrastructure-together-ai
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints
Open skill

