The choice of fetch vs axios in Next.js Server Components comes down to integration. fetch is built into the runtime and understood by the framework, while axios is a library you install for interceptors, timeouts, and automatic JSON parsing.
In a Server Component, fetch gets request deduplication and the Next.js cache options for free, and axios gets none of that. Both can load JSON, so the decision is about integration and conveniences, not about capability.
| fetch | axios | |
|---|---|---|
| Dependency | Built in | npm install axios |
| Next.js integration | Deduplicated, cache options | None |
| Response body | res.json() | response.data, already parsed |
| Interceptors | No | Yes |
| Timeout | AbortSignal.timeout | timeout option |
What fetch gives you for free
Next.js memoizes GET requests that share a URL and options within a single render, so a layout and a page calling the same endpoint only hit the network once. It also accepts the cache, next.revalidate, and next.tags options described in using fetch in Next.js.
// app/posts/page.tsx
type Post = { id: number; title: string };
export default async function PostsPage() {
const res = await fetch("https://api.example.com/posts", {
cache: "force-cache",
});
const posts: Post[] = await res.json();
return <ul>{posts.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}This page stores the response in the framework cache without a single dependency beyond the runtime.
What axios adds
axios is a full HTTP client. It supports request and response interceptors, instance defaults, request timeouts, and progress events, and it parses JSON into response.data automatically.
// app/posts/page.tsx
import axios from "axios";
type Post = { id: number; title: string };
export default async function PostsPage() {
const { data } = await axios.get<Post[]>("https://api.example.com/posts", {
timeout: 5000,
});
return <ul>{data.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}The response body arrives as data with no manual res.json call, and the request rejects after five seconds if the server does not answer. fetch has no timeout option of its own, so if you need a request to give up after a fixed number of seconds, you either wire up AbortSignal.timeout yourself or let axios handle it. Interceptors are the other gap: axios runs a chain of handlers before and after each request, which fetch cannot do.
Which one to choose
Use fetch when the data belongs to a Server Component, because you get deduplication and caching without thinking about it. Use axios when you want interceptors, global headers, or timeouts, or when the same client must run in the browser with shared defaults.
Most Server Component work is a job for fetch. axios earns its place in client-side code where a shared instance with a base URL and an auth interceptor removes boilerplate from every call.
The deduplication caveat
Next.js memoizes fetch requests that share a URL and options within one render. axios requests are not memoized, so a layout and a page calling the same axios helper send two requests to your API instead of one, which shows up as doubled load and faster rate limiting.
The fix is to wrap the axios helper in React's cache function, which memoizes any async function for the length of one server request. For the full distinction, see request deduplication vs React cache.
Rune AI
Key Insights
- fetch is built in and gets Next.js memoization and cache options.
- axios adds interceptors, timeouts, and automatic JSON parsing.
- axios requests are not memoized, so repeated calls hit the network twice.
- Use fetch for server data, axios for a shared client with global config.
Frequently Asked Questions
Does axios work in a Server Component?
Which is faster?
When should I still choose axios?
Conclusion
fetch is the right default for Server Components because it is built in, deduplicated, and cacheable by Next.js. axios earns its dependency when interceptors, timeouts, and a shared client are more important than that integration.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.