Fetching Data
This page will walk you through how you can fetch data inServer and Client Components, and how tostream components that depend on data.
Fetching data
Server Components
You can fetch data in Server Components using:
With thefetch
API
To fetch data with thefetch
API, turn your component into an asynchronous function, and await thefetch
call. For example:
exportdefaultasyncfunctionPage() {constdata=awaitfetch('https://api.vercel.app/blog')constposts=awaitdata.json()return ( <ul> {posts.map((post)=> ( <likey={post.id}>{post.title}</li> ))} </ul> )}
Good to know:
fetch
responses are not cached by default. However, Next.js willprerender the route and the output will be cached for improved performance. If you'd like to opt intodynamic rendering, use the{ cache: 'no-store' }
option. See thefetch
API Reference.- During development, you can log
fetch
calls for better visibility and debugging. See thelogging
API reference.
With an ORM or database
Since Server Components are rendered on the server, you can safely make database queries using an ORM or database client. Turn your component into an asynchronous function, and await the call:
import { db, posts }from'@/lib/db'exportdefaultasyncfunctionPage() {constallPosts=awaitdb.select().from(posts)return ( <ul> {allPosts.map((post)=> ( <likey={post.id}>{post.title}</li> ))} </ul> )}
Client Components
There are two ways to fetch data in Client Components, using:
- React's
use
hook - A community library likeSWR orReact Query
Streaming data with theuse
hook
You can use React'suse
hook tostream data from the server to client. Start by fetching data in your Server component, and pass the promise to your Client Component as prop:
import Postsfrom'@/app/ui/postsimport { Suspense }from'react'exportdefaultfunctionPage() {// Don't await the data fetching functionconstposts=getPosts()return ( <Suspensefallback={<div>Loading...</div>}> <Postsposts={posts} /> </Suspense> )}
Then, in your Client Component, use theuse
hook to read the promise:
'use client'import { use }from'react'exportdefaultfunctionPosts({ posts,}: { posts:Promise<{ id:string; title:string }[]>}) {constallPosts=use(posts)return ( <ul> {allPosts.map((post)=> ( <likey={post.id}>{post.title}</li> ))} </ul> )}
In the example above, the<Posts>
component is wrapped in a<Suspense>
boundary. This means the fallback will be shown while the promise is being resolved. Learn more aboutstreaming.
Community libraries
You can use a community library likeSWR orReact Query to fetch data in Client Components. These libraries have their own semantics for caching, streaming, and other features. For example, with SWR:
'use client'import useSWRfrom'swr'constfetcher= (url)=>fetch(url).then((r)=>r.json())exportdefaultfunctionBlogPage() {const {data,error,isLoading }=useSWR('https://api.vercel.app/blog', fetcher )if (isLoading)return <div>Loading...</div>if (error)return <div>Error: {error.message}</div>return ( <ul> {data.map((post: { id:string; title:string })=> ( <likey={post.id}>{post.title}</li> ))} </ul> )}
Deduplicate requests and cache data
One way to deduplicatefetch
requests is withrequest memoization. With this mechanism,fetch
calls usingGET
orHEAD
with the same URL and options in a single render pass are combined into one request. This happens automatically, and you canopt out by passing an Abort signal tofetch
.
Request memoization is scoped to the lifetime of a request.
You can also deduplicatefetch
requests by using Next.js’Data Cache, for example by settingcache: 'force-cache'
in yourfetch
options.
Data Cache allows sharing data across the current render pass and incoming requests.
If you arenot usingfetch
, and instead using an ORM or database directly, you can wrap your data access with theReactcache
function.
import { cache }from'react'import { db, posts, eq }from'@/lib/db'exportconstgetPost=cache(async (id:string)=> {constpost=awaitdb.query.posts.findFirst({ where:eq(posts.id,parseInt(id)), })})
Streaming
Warning: The content below assumes the
dynamicIO
config option is enabled in your application. The flag was introduced in Next.js 15 canary.
When usingasync/await
in Server Components, Next.js will opt intodynamic rendering. This means the data will be fetched and rendered on the server for every user request. If there are any slow data requests, the whole route will be blocked from rendering.
To improve the initial load time and user experience, you can use streaming to break up the page's HTML into smaller chunks and progressively send those chunks from the server to the client.


There are two ways you can implement streaming in your application:
- Wrapping a page with a
loading.js
file - Wrapping a component with
<Suspense>
Withloading.js
You can create aloading.js
file in the same folder as your page to stream theentire page while the data is being fetched. For example, to streamapp/blog/page.js
, add the file inside theapp/blog
folder.


exportdefaultfunctionLoading() {// Define the Loading UI herereturn <div>Loading...</div>}
On navigation, the user will immediately see the layout and aloading state while the page is being rendered. The new content will then be automatically swapped in once rendering is complete.


Behind-the-scenes,loading.js
will be nested insidelayout.js
, and will automatically wrap thepage.js
file and any children below in a<Suspense>
boundary.


This approach works well for route segments (layouts and pages), but for more granular streaming, you can use<Suspense>
.
With<Suspense>
<Suspense>
allows you to be more granular about what parts of the page to stream. For example, you can immediately show any page content that falls outside of the<Suspense>
boundary, and stream in the list of blog posts inside the boundary.
import { Suspense }from'react'import BlogListfrom'@/components/BlogList'import BlogListSkeletonfrom'@/components/BlogListSkeleton'exportdefaultfunctionBlogPage() {return ( <div> {/* This content will be sent to the client immediately */} <header> <h1>Welcome to the Blog</h1> <p>Read the latest posts below.</p> </header> <main> {/* Any content wrapped in a <Suspense> boundary will be streamed */} <Suspensefallback={<BlogListSkeleton />}> <BlogList /> </Suspense> </main> </div> )}
Creating meaningful loading states
An instant loading state is fallback UI that is shown immediately to the user after navigation. For the best user experience, we recommend designing loading states that are meaningful and help users understand the app is responding. For example, you can use skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc.
In development, you can preview and inspect the loading state of your components using theReact Devtools.
Examples
Sequential data fetching
Sequential data fetching happens when nested components in a tree each fetch their own data and the requests are notdeduplicated, leading to longer response times.


There may be cases where you want this pattern because one fetch depends on the result of the other.
For example, the<Playlists>
component will only start fetching data once the<Artist>
component has finished fetching data because<Playlists>
depends on theartistID
prop:
exportdefaultasyncfunctionPage({ params,}: { params:Promise<{ username:string }>}) {const {username }=await params// Getartist informationconstartist=awaitgetArtist(username)return ( <> <h1>{artist.name}</h1> {/* Show fallback UI while the Playlists component is loading */} <Suspensefallback={<div>Loading...</div>}> {/* Pass theartist ID to the Playlists component */} <PlaylistsartistID={artist.id} /> </Suspense> </> )}asyncfunctionPlaylists({artistID }: {artistID:string }) {// Use theartist ID to fetch playlistsconstplaylists=awaitgetArtistPlaylists(artistID)return ( <ul> {playlists.map((playlist)=> ( <likey={playlist.id}>{playlist.name}</li> ))} </ul> )}
To improve the user experience, you should useReact<Suspense>
to show afallback
while data is being fetch. This will enablestreaming and prevent the whole route from being blocked by the sequential data requests.
Parallel data fetching
Parallel data fetching happens when data requests in a route are eagerly initiated and start at the same time.
By default,layouts and pages are rendered in parallel. So each segment starts fetching data as soon as possible.
However, withinany component, multipleasync
/await
requests can still be sequential if placed after the other. For example,getAlbums
will be blocked untilgetArtist
is resolved:
import { getArtist, getAlbums }from'@/app/lib/data'exportdefaultasyncfunctionPage({ params }) {// These requests will be sequentialconst {username }=await paramsconstartist=awaitgetArtist(username)constalbums=awaitgetAlbums(username)return <div>{artist.name}</div>}
You can initiate requests in parallel by defining them outside the components that use the data, and resolving them together, for example, withPromise.all
:
import Albumsfrom'./albums'asyncfunctiongetArtist(username:string) {constres=awaitfetch(`https://api.example.com/artist/${username}`)returnres.json()}asyncfunctiongetAlbums(username:string) {constres=awaitfetch(`https://api.example.com/artist/${username}/albums`)returnres.json()}exportdefaultasyncfunctionPage({ params,}: { params:Promise<{ username:string }>}) {const {username }=await paramsconstartistData=getArtist(username)constalbumsData=getAlbums(username)// Initiate both requests in parallelconst [artist,albums]=awaitPromise.all([artistData, albumsData])return ( <> <h1>{artist.name}</h1> <Albumslist={albums} /> </> )}
Good to know: If one request fails when using
Promise.all
, the entire operation will fail. To handle this, you can use thePromise.allSettled
method instead.
Preloading data
You can preload data by creating an utility function that you eagerly call above blocking requests.<Item>
conditionally renders based on thecheckIsAvailable()
function.
You can callpreload()
beforecheckIsAvailable()
to eagerly initiate<Item/>
data dependencies. By the time<Item/>
is rendered, its data has already been fetched.
import { getItem, checkIsAvailable }from'@/lib/data'exportdefaultasyncfunctionPage({ params,}: { params:Promise<{ id:string }>}) {const {id }=await params// starting loadingitem datapreload(id)// perform another asynchronous taskconstisAvailable=awaitcheckIsAvailable()return isAvailable? <Itemid={id} />:null}exportconstpreload= (id:string)=> {// void evaluates the given expression and returns undefined// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/voidvoidgetItem(id)}exportasyncfunctionItem({ id }: { id:string }) {constresult=awaitgetItem(id)// ...}
Additionally, you can use React'scache
function and theserver-only
package to create a reusable utility function. This approach allows you to cache the data fetching function and ensure that it's only executed on the server.
import { cache }from'react'import'server-only'import { getItem }from'@/lib/data'exportconstpreload= (id:string)=> {voidgetItem(id)}exportconstgetItem=cache(async (id:string)=> {// ...})
API Reference
Data Security
fetch
loading.js
logging
taint
Was this helpful?