Error: `getServerSideProps` is not supported in app/ directory
Error: `getStaticProps` is not supported in app/ directory
Youβre using Pages Router data-fetching functions (getServerSideProps, getStaticProps, getStaticPaths) inside the App Routerβs app/ directory. These APIs donβt exist in the App Router.
Why this happens
Next.js has two routing systems that coexist but use completely different patterns:
Pages Router (pages/) | App Router (app/) | |
|---|---|---|
| Data fetching | getServerSideProps, getStaticProps | async Server Components, fetch() |
| Components | Client Components by default | Server Components by default |
| Layouts | _app.tsx, _document.tsx | layout.tsx (nested) |
| API routes | pages/api/*.ts | app/api/*/route.ts |
| Available since | Next.js 1 | Next.js 13.4+ |
When you place a file in app/ and export getServerSideProps, Next.js throws an error because that function has no meaning in the App Router context.
Fix 1: Convert to async Server Component (most common)
In the App Router, components are Server Components by default. You can await data directly in the component β no special function needed.
// β Pages Router pattern β doesn't work in app/
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
export default function PostsPage({ posts }) {
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
// β
App Router equivalent β app/posts/page.tsx
export default async function PostsPage() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
No wrapper function, no props object. The component itself is async and fetches its own data on the server.
Fix 2: Convert getStaticProps to cached fetch
getStaticProps generated static pages at build time. In the App Router, you achieve the same with fetch() and caching options.
// β Pages Router
export async function getStaticProps() {
const posts = await getPosts();
return { props: { posts }, revalidate: 60 };
}
// β
App Router β static by default, revalidate with next.revalidate
export default async function PostsPage() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 }, // ISR: revalidate every 60 seconds
});
const posts = await res.json();
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
Caching behavior:
fetch(url)β cached indefinitely (likegetStaticPropswithout revalidate)fetch(url, { next: { revalidate: 60 } })β ISR, revalidates every 60sfetch(url, { cache: 'no-store' })β never cached (likegetServerSideProps)
Fix 3: Convert getStaticPaths to generateStaticParams
// β Pages Router
export async function getStaticPaths() {
const posts = await getPosts();
return {
paths: posts.map(p => ({ params: { slug: p.slug } })),
fallback: 'blocking',
};
}
// β
App Router β app/posts/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map(p => ({ slug: p.slug }));
}
export default async function PostPage({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return <article><h1>{post.title}</h1><p>{post.content}</p></article>;
}
Fix 4: Move the file to pages/ if you want to keep using Pages Router
If youβre not ready to migrate, simply keep the file in pages/:
pages/posts/index.tsx β getServerSideProps works here
app/posts/page.tsx β use Server Components here (don't have both!)
Important: Donβt have the same route in both pages/ and app/. If both exist, Next.js uses the app/ version and ignores pages/.
Fix 5: Convert metadata (head/SEO)
If you used getServerSideProps primarily for SEO metadata:
// β Pages Router β fetching data just for <Head>
export async function getServerSideProps({ params }) {
const post = await getPost(params.slug);
return { props: { post } };
}
// Then using <Head><title>{post.title}</title></Head>
// β
App Router β use generateMetadata
export async function generateMetadata({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: { title: post.title, images: [post.coverImage] },
};
}
export default async function PostPage({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return <article>{post.content}</article>;
}
Next.js deduplicates the getPost() call β if both generateMetadata and the page component call it with the same arguments, it only executes once.
Fix 6: Convert API routes
// β Pages Router β pages/api/users.ts
export default function handler(req, res) {
if (req.method === 'GET') {
const users = getUsers();
res.json(users);
}
}
// β
App Router β app/api/users/route.ts
export async function GET() {
const users = await getUsers();
return Response.json(users);
}
export async function POST(request: Request) {
const body = await request.json();
const user = await createUser(body);
return Response.json(user, { status: 201 });
}
Migration strategy
Donβt migrate everything at once. Next.js supports both routers simultaneously:
- Keep existing
pages/routes working - Create new routes in
app/ - Migrate one route at a time: create in
app/, test, then delete frompages/ - Migrate layouts last (
_app.tsxβapp/layout.tsx)
Common mistakes during migration
Forgetting 'use client' for interactive components:
// β useState doesn't work in Server Components
export default function Counter() {
const [count, setCount] = useState(0); // Error!
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
// β
Add 'use client' directive
'use client';
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
Trying to pass functions as props from Server to Client Components:
// β Can't pass functions across the server/client boundary
<ClientComponent onSubmit={async (data) => { await saveToDb(data) }} />
// β
Use Server Actions instead
'use server';
async function submitForm(data: FormData) {
await saveToDb(Object.fromEntries(data));
}
FAQ
Can I use getServerSideProps and App Router in the same project?
Yes, but not for the same route. pages/about.tsx can use getServerSideProps while app/dashboard/page.tsx uses Server Components. They coexist at the project level.
Is the App Router faster than getServerSideProps?
For most cases, yes. Server Components stream HTML progressively (with Suspense), while getServerSideProps blocks the entire page until all data is fetched. The App Router also deduplicates fetch requests automatically.
How do I access cookies/headers in the App Router?
import { cookies, headers } from 'next/headers';
export default async function Page() {
const cookieStore = cookies();
const token = cookieStore.get('session')?.value;
const headersList = headers();
const userAgent = headersList.get('user-agent');
// ...
}
What replaces context.req and context.res from getServerSideProps?
In the App Router, use cookies(), headers(), and redirect() from next/headers and next/navigation. For full request/response access, use Route Handlers (route.ts).