This error occurs when attempting to use the fetch API without properly declaring the containing function as async. In Next.js, fetch must be called with await inside an async function, particularly in Server Components.
This error appears when you try to use the `fetch()` API but haven't declared your function as `async`. The fetch API is promise-based and requires the use of `await` to handle the response, which means the containing function must be marked with the `async` keyword. In Next.js with the App Router, this commonly occurs when developers try to fetch data in components without properly using async/await syntax. Next.js Server Components support async functions, allowing you to fetch data directly in the component, but the component function must be declared as async. The error can also occur if you try to make a Client Component async, which is not supported in React. Client Components marked with `'use client'` cannot be async functions, and attempting to do so will trigger similar errors.
If you're fetching data in a Server Component (default in Next.js App Router), simply add the async keyword to your component function:
// Before - incorrect
export default function Page() {
const data = fetch('https://api.example.com/data'); // Error!
return <div>{/* ... */}</div>;
}
// After - correct
export default async function Page() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return <div>{/* ... */}</div>;
}Server Components can be async and support direct fetch calls with await.
If your component is marked with 'use client' but doesn't actually need client-side interactivity, remove the directive and make it an async Server Component:
// Remove this if not needed
// 'use client'
export default async function Page() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return <div>{data.title}</div>;
}This is the recommended approach for data fetching in Next.js 13+.
If you must fetch data in a Client Component, use the useEffect hook with state management:
'use client'
import { useState, useEffect } from 'react';
export default function ClientPage() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
}
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{data?.title}</div>;
}Note: Client-side fetching is generally not recommended when Server Components can be used.
For more robust client-side data fetching, use established libraries like SWR or React Query:
'use client'
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then(res => res.json());
export default function ClientPage() {
const { data, error, isLoading } = useSWR(
'https://api.example.com/data',
fetcher
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading data</div>;
return <div>{data.title}</div>;
}These libraries provide caching, revalidation, and better error handling out of the box.
For advanced cases, fetch data in a Server Component and pass the promise to a Client Component using React's use hook:
// app/page.tsx (Server Component)
import ClientComponent from './ClientComponent';
export default function Page() {
const dataPromise = fetch('https://api.example.com/data')
.then(res => res.json());
return <ClientComponent dataPromise={dataPromise} />;
}
// ClientComponent.tsx
'use client'
import { use } from 'react';
export default function ClientComponent({
dataPromise
}: {
dataPromise: Promise<any>
}) {
const data = use(dataPromise);
return <div>{data.title}</div>;
}This pattern allows Server Components to initiate the fetch while Client Components handle the data.
TypeScript Requirements: To use async Server Components with TypeScript, you need TypeScript 5.1.3 or higher and @types/react 18.2.8 or higher.
Caching Behavior: Next.js automatically caches fetch requests in Server Components by default. The data can be fetched at build time or request time and reused across requests. Use the cache and next.revalidate options to control this behavior:
const response = await fetch('https://api.example.com/data', {
cache: 'force-cache', // or 'no-store'
next: { revalidate: 3600 } // revalidate every hour
});Route Handlers and Server Actions: You can also use async/await with fetch in Route Handlers (API routes) and Server Actions. These contexts always support async functions regardless of whether they're Server or Client Components.
Error Boundaries: When using async Server Components, wrap them in error boundaries to handle fetch failures gracefully. Create an error.tsx file in your route directory to catch and handle errors.
Streaming and Suspense: Server Components with async data fetching work seamlessly with React Suspense and Next.js streaming. Wrap async components in Suspense boundaries to show loading states while data is being fetched.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite