Search across all documentation pages
Pass null or a falsy value as the key to prevent SWR from fetching. Use this to wait for dependencies, gate requests behind authentication, or chain sequential fetches.
"use client";
import useSWR from "swr";
function UserProjects({ userId }: { userId: string | null }) {
// Won't fetch until userId is available
const { data } = useSWR(userId ? `/api/users/${userId}/projects` : null, fetcher);
return <div>{data?.length ?? 0} projects</div>;
}"use client";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
interface User {
id
null, undefined, false, or "", SWR skips the fetch entirely and returns { data: undefined, error: undefined, isLoading: false }.() => condition ? key : null is also supported and evaluated on every render.Key as a function:
const { data } = useSWR(
() => (isLoggedIn ? `/api/profile` : null),
fetcher
);Multiple dependencies:
const { data: user } = useSWR("/api/me", fetcher);
const { data: org } = useSWR(user ? `/api/orgs/${user.orgId}` : null, fetcher);
const { data
Conditional with array key:
const { data } = useSWR(
token ? ["/api/data", token] : null,
([url, token]) =>
fetch(url, { headers: { Authorization: `Bearer ${token}` } }).then((r)
Throw in key function to pause:
// Throwing inside the key function also pauses fetching
const { data } = useSWR(
() => `/api/users/${userId ?? throwUndefined()}`,
fetcher
);
function throwUndefined(): never {
throw new Error(
Data | undefined since the fetch may not have run yet.null, TypeScript infers the key type as null. Use a union type or generic to keep it clean.const { data } = useSWR<Team>(
user ? `/api/teams/${user.teamId}` : null,
fetcher
);
// data: Team | undefinednull to a real value, isLoading becomes true for that transition. Plan your loading UI accordingly.null key. However, thrown errors in the key function are silently caught and do not appear in error.| Approach | Pros | Cons |
|---|---|---|
| Null key (SWR) | Declarative, automatic trigger on change | Creates waterfall for dependent fetches |
| enabled option (React Query) | Explicit boolean flag | Not available in SWR natively |
| useEffect guard | Familiar imperative pattern | Loses SWR caching and dedup benefits |
| Server-side join | Single request, no waterfall | Requires API changes, less flexible |
SWR skips the fetch when the key is null, undefined, false, or an empty string "". Any of these falsy values will prevent the request.
It returns { data: undefined, error: undefined, isLoading: false }. No fetch is made at all -- isLoading is false because there is nothing to load.
Derive the second request's key from the first request's data:
const { data: user } = useSWR("/api/me", fetcher);
const { data: team } = useSWR(
user ? `/api/teams/${user.teamId}` : null,
Yes. SWR evaluates a key function on every render:
const { data } = useSWR(
() => (isLoggedIn ? `/api/profile` : null),
fetcher
);Yes. Each chained request waits for the previous one. Keep dependency chains short (2-3 max) to avoid slow page loads. If possible, combine data into a single API endpoint on the server side.
SWR treats a thrown error inside the key function the same as a null key -- it pauses fetching. However, the error is silently caught and does not appear in the error return value.
const { data } = useSWR(
token ? ["/api/data", token] : null,
([url, token]) =>
fetch(url, {
headers: { Authorization: `Bearer ${token}` },
}).
No. A null key means "do not fetch." It is not an error state. error remains undefined and isLoading is false. Do not confuse conditional fetching with error handling.
The data type remains Data | undefined since the fetch may not have run yet. Use a union type or generic to keep it clean:
const { data } = useSWR<Team>(
user ? `/api/teams/${user.teamId}` : null,
fetcher
);
// data: Team | undefinedisLoading becomes true for that transition while SWR fetches data for the newly-truthy key. Plan your loading UI to account for this state change.
SWR uses null/falsy keys to prevent fetching, while React Query has an explicit enabled boolean option. SWR's approach is declarative and key-driven; React Query's is more explicit but not available natively in SWR.
The team fetch runs only after user is available.