swr
Skill275 starsChanged 36 days agoApache-2.0View on GitHub
Guidelines for using SWR (stale-while-revalidate) React Hooks for efficient data fetching, caching, and revalidation
- Sends data out
2 other projects use a version of this.
Adopted by
Most recently taken up by
- Firzus/agent-skillstheir own version, first seen Oct 23, 2026
- openai/pluginstheir own version, first seen Oct 13, 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
- Firzus/agent-skills★ 4same 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 repository264 other files it gives its agents.
- accessibility-a11ySkill
- alpine-jsSkill
- analytics-data-analysisSkill
- android-developmentSkill
- angular-developmentSkill
- angularSkill
- anime-jsSkill
- anthropic-claude-developmentSkill
- api-developmentSkill
- apollo-graphqlSkill
- aspnet-coreSkill
- astroSkill
- auth0-authenticationSkill
- autogen-developmentSkill
- automl-hyperparameter-optimizationSkill
- aws-developmentSkill
- azureSkill
- backend-developmentSkill
- bash-scriptingSkill
- beautifulsoup-parsingSkill
- bitbucket-workflowSkill
- blazorSkill
- blender-python-addonSkill
- blockchainSkill
- bootstrapSkill
- business-central-developmentSkill
- cheerio-parsingSkill
- chrome-extension-developmentSkill
- ci-cd-best-practicesSkill
- clean-architectureSkill
- clean-codeSkill
- clerk-authenticationSkill
- cloudflare-developmentSkill
- computer-vision-opencvSkill
- convexSkill
- cppSkill
- c-sharpSkill
- cssSkill
- cypressSkill
- data-analysis-jupyterSkill
- data-analystSkill
- data-jupyter-pythonSkill
- deep-learning-pythonSkill
- deep-learning-pytorchSkill
- deep-learningSkill
- deno-typescriptSkill
- design-systemsSkill
- devopsSkill
- django-pythonSkill
- django-rest-api-developmentSkill
- dockerSkill
- dotnetSkill
- drizzle-ormSkill
- drupal-developmentSkill
- elasticsearch-best-practicesSkill
- electron-developmentSkill
- elixirSkill
- embedded-stm32Skill
- esbuild-bundlerSkill
- ethereumSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 9 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Use SWR for all client-side data fetching
- Distinctive: line 19
Use TypeScript for full type safety
- Distinctive: line 412
Use SWR for client-side data fetching with minimal configuration
- Distinctive: line 415
Use prefetching to improve performance before users request data
- Very specific: line 417
Use useSWRInfinite for paginated and infinite scroll patterns
- Very specific: line 442
Do not use useEffect for data fetching when SWR can handle it
- Distinctive: line 443
Do not ignore error states - always provide user feedback
- Distinctive: line 444
Do not forget to handle loading states appropriately
- Distinctive: line 445
Do not use polling when WebSocket or SSE would be more efficient
- Distinctive: line 446
Do not skip conditional fetching for dependent data
- Distinctive: line 447
Do not ignore TypeScript types for fetched data
≈ “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 Best Practices
You are an expert in SWR (stale-while-revalidate), TypeScript, and React development. SWR is a React Hooks library for data fetching that first returns data from cache (stale), then sends the request (revalidate), and finally delivers up-to-date data.
Core Principles
- Use SWR for all client-side data fetching
- Leverage automatic caching and revalidation
- Minimize boilerplate with SWR's built-in state management
- Implement proper error handling and loading states
- Use TypeScript for full type safety
Key Features
- Stale-While-Revalidate: Returns cached data immediately, then revalidates in background
- Automatic Revalidation: On mount, window focus, and network reconnection
- Request Deduplication: Multiple components using same key share one request
- Built-in Caching: Zero-configuration caching with smart invalidation
- Minimal API: Simple hook-based interface
Project Structure
src/
hooks/
swr/
useUser.ts
usePosts.ts
useProducts.ts
lib/
fetcher.ts # Global fetcher configuration
providers/
SWRProvider.tsx # SWR configuration provider
types/
api.ts # API response typesSetup and Configuration
Global Configuration
// providers/SWRProvider.tsx
import { SWRConfig } from 'swr';
const fetcher = async (url: string) => {
const res = await fetch(url);
if (!res.ok) {
const error = new Error('An error occurred while fetching data.');
throw error;
}
return res.json();
};
export function SWRProvider({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher,
revalidateOnFocus: true,
revalidateOnReconnect: true,
shouldRetryOnError: true,
errorRetryCount: 3,
dedupingInterval: 2000,
}}
>
{children}
</SWRConfig>
);
}Custom Fetcher
// lib/fetcher.ts
export async function fetcher<T>(url: string): Promise<T> {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// With authentication
export async function authFetcher<T>(url: string): Promise<T> {
const token = getAuthToken();
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}Basic Usage
useSWR Hook
The useSWR hook accepts three parameters:
- key: A unique string identifier for the request (like a URL)
- fetcher: An async function that fetches the data
- options: Configuration options
import useSWR from 'swr';
interface User {
id: string;
name: string;
email: string;
}
function useUser(userId: string) {
const { data, error, isLoading, isValidating, mutate } = useSWR<User>(
userId ? `/api/users/${userId}` : null,
fetcher
);
return {
user: data,
isLoading,
isError: !!error,
isValidating,
mutate,
};
}Conditional Fetching
Pass null or a falsy value as key to conditionally skip fetching:
// Only fetch when userId is available
const { data } = useSWR(userId ? `/api/users/${userId}` : null, fetcher);
// Using a function for dynamic keys
const { data } = useSWR(() => `/api/users/${userId}`, fetcher);Revalidation Strategies
Automatic Revalidation
SWR automatically revalidates data in three cases:
- Component is mounted (even with cached data)
- Window gains focus
- Browser regains network connection
// Disable specific revalidation behaviors
const { data } = useSWR('/api/data', fetcher, {
revalidateOnFocus: false,
revalidateOnReconnect: false,
revalidateOnMount: true,
});Manual Revalidation
import { useSWRConfig } from 'swr';
function UpdateButton() {
const { mutate } = useSWRConfig();
const handleUpdate = async () => {
// Revalidate specific key
await mutate('/api/users');
// Revalidate all keys matching a filter
await mutate(
(key) => typeof key === 'string' && key.startsWith('/api/users'),
undefined,
{ revalidate: true }
);
};
return <button onClick={handleUpdate}>Refresh</button>;
}Polling / Interval Refresh
// Refresh every 3 seconds
const { data } = useSWR('/api/realtime', fetcher, {
refreshInterval: 3000,
});
// Conditional polling
const { data } = useSWR('/api/realtime', fetcher, {
refreshInterval: isVisible ? 1000 : 0,
});Mutation Patterns
Optimistic Updates
import useSWR, { useSWRConfig } from 'swr';
function useUpdateUser() {
const { mutate } = useSWRConfig();
const updateUser = async (userId: string, newData: Partial<User>) => {
// Optimistic update
await mutate(
`/api/users/${userId}`,
async (currentData: User | undefined) => {
// Update API
const updated = await fetch(`/api/users/${userId}`, {
method: 'PATCH',
body: JSON.stringify(newData),
}).then(r => r.json());
return updated;
},
{
optimisticData: (current) => ({ ...current, ...newData } as User),
rollbackOnError: true,
populateCache: true,
revalidate: false,
}
);
};
return { updateUser };
}Bound Mutate
function UserProfile({ userId }: { userId: string }) {
const { data: user, mutate } = useSWR(`/api/users/${userId}`, fetcher);
const handleUpdate = async (newName: string) => {
// Update local data immediately
mutate({ ...user, name: newName }, false);
// Send update to server
await updateUserName(userId, newName);
// Revalidate to ensure consistency
mutate();
};
return (
<div>
<p>{user?.name}</p>
<button onClick={() => handleUpdate('New Name')}>Update</button>
</div>
);
}Pagination
Basic Pagination
function usePaginatedUsers(page: number) {
return useSWR(`/api/users?page=${page}`, fetcher, {
keepPreviousData: true,
});
}Infinite Loading with useSWRInfinite
import useSWRInfinite from 'swr/infinite';
function useInfiniteUsers() {
const getKey = (pageIndex: number, previousPageData: User[] | null) => {
// Return null to stop fetching
if (previousPageData && previousPageData.length === 0) return null;
// Return key for next page
return `/api/users?page=${pageIndex + 1}`;
};
const { data, error, size, setSize, isValidating } = useSWRInfinite(
getKey,
fetcher
);
const users = data ? data.flat() : [];
const isLoadingMore = size > 0 && data && typeof data[size - 1] === 'undefined';
const isEmpty = data?.[0]?.length === 0;
const isReachingEnd = isEmpty || (data && data[data.length - 1]?.length < 10);
return {
users,
isLoadingMore,
isReachingEnd,
loadMore: () => setSize(size + 1),
};
}Cursor-Based Pagination
import useSWRInfinite from 'swr/infinite';
function useCursorPagination() {
const getKey = (pageIndex: number, previousPageData: any) => {
if (previousPageData && !previousPageData.nextCursor) return null;
if (pageIndex === 0) return '/api/items';
return `/api/items?cursor=${previousPageData.nextCursor}`;
};
return useSWRInfinite(getKey, fetcher);
}Error Handling
Component-Level Error Handling
function UserProfile({ userId }: { userId: string }) {
const { data, error, isLoading } = useSWR(`/api/users/${userId}`, fetcher);
if (isLoading) return <Skeleton />;
if (error) {
return (
<ErrorMessage
message="Failed to load user profile"
retry={() => mutate(`/api/users/${userId}`)}
/>
);
}
return <ProfileCard user={data} />;
}Global Error Handler
<SWRConfig
value={{
onError: (error, key) => {
if (error.status !== 403 && error.status !== 404) {
// Send error to tracking service
reportError(error, key);
}
},
}}
>
<App />
</SWRConfig>Prefetching
import { preload } from 'swr';
// Prefetch data before component renders
function prefetchUser(userId: string) {
preload(`/api/users/${userId}`, fetcher);
}
// Usage: Call on hover or route change
function UserLink({ userId }: { userId: string }) {
return (
<Link
to={`/users/${userId}`}
onMouseEnter={() => prefetchUser(userId)}
>
View Profile
</Link>
);
}Key Conventions
- Use SWR for client-side data fetching with minimal configuration
- Implement conditional rendering for loading states and error messages
- Validate data to ensure expected format and handle errors gracefully
- Use prefetching to improve performance before users request data
- Leverage automatic revalidation for real-time data freshness
- Use
useSWRInfinitefor paginated and infinite scroll patterns
Integration with Next.js
// For server-side data, use getServerSideProps or getStaticProps
// For client-side caching and revalidation, use SWR
// pages/user/[id].tsx
export async function getStaticProps({ params }) {
const user = await fetchUser(params.id);
return { props: { fallback: { [`/api/users/${params.id}`]: user } } };
}
export default function UserPage({ fallback }) {
return (
<SWRConfig value={{ fallback }}>
<UserProfile />
</SWRConfig>
);
}Anti-Patterns to Avoid
- Do not use
useEffectfor data fetching when SWR can handle it - Do not ignore error states - always provide user feedback
- Do not forget to handle loading states appropriately
- Do not use polling when WebSocket or SSE would be more efficient
- Do not skip conditional fetching for dependent data
- Do not ignore TypeScript types for fetched data
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.

