Przejdź do treści

App Router czy Pages Router — co wybrać?

App Router czy Pages Router w Next.js 16? Konkretne różnice, koszty migracji i praktyczne kryteria wyboru dla nowych oraz istniejących projektów.

Maciej Sala

Founder StriveLab

8 min czytaniaOpublikowano 23 grudnia 2025 (Aktualizacja 25 maja 2026)

W 2026 oba routery są nadal wspierane, ale większość nowych możliwości Next.js trafia najpierw do App Router. W tym artykule porównam oba rozwiązania bez marketingowego szumu i pokażę nie tylko zalety, ale też realny koszt migracji, granice ekosystemu i momenty, w których Pages Router wciąż bywa rozsądnym wyborem.

App Router vs Pages Router: szybkie porównanie

KryteriumPages RouterApp Router
Folderpages/app/
Domyślny typ komponentuClient ComponentServer Component
Pobieranie danychgetServerSideProps, getStaticPropsasync component, fetch()
Layouty_app.tsx + getLayout patternNatywne, zagnieżdżone, zachowują stan
Loading/Error statesRęczna implementacjaPlik loading.tsx / error.tsx
Metadata / next/headMetadata z TypeScript
sizeWiększy (cały kod do klienta)Mniejszy (Server Components)
StreamingBrakWbudowany z Suspense
Status wsparciaUtrzymywany, bez nowych funkcjiAktywny rozwój, nowe funkcje
Krzywa uczenia sięNiska dla znających ReactWyższa (RSC, Server Actions, cache)
Kiedy wybraćIstniejący projekt, proste strony, stabilnośćNowe projekty, dashboard, SSaaS, SEO-heavy

Czym różni się App Router od Pages Router?

Zanim przejdziemy do szczegółów, warto zwrócić uwagę na fundamentalną różnicę:

Pages Router to tradycyjny routing Next.js, w którym pliki w folderze pages/ automatycznie stają się trasami. Komponenty są Client Components z opcjonalnym / przez getServerSideProps i getStaticProps.

App Router — kluczowe w nim są komponenty serwerowe z biblioteką React Server Components wy routing w folderze app/, omyślnie wszystkie komponenty to Server Components,a layouts, loading states i error boundaries są wbudowane w strukturę folderów.

Code
# Pages Router
pages/
├── index.tsx          → /
├── about.tsx          → /about
├── blog/
│   ├── index.tsx      → /blog
│   └── [slug].tsx     → /blog/:slug
└── _app.tsx           → wrapper dla wszystkich stron

# App Router
app/
├── page.tsx           → /
├── layout.tsx         → wrapper (dziedziczony)
├── about/
│   └── page.tsx       → /about
└── blog/
    ├── page.tsx       → /blog
    └── [slug]/
        └── page.tsx   → /blog/:slug

Kluczowe różnice między App Router i Pages Router

1. Pobieranie danych w App Router i Pages Router

Tutaj zaszła największa zmiana i jest to też źródło największych komplikacji

Pages Router — dedykowane funkcje eksportowane z komponentu strony:

Code
// pages/blog/[slug].tsx
export async function getStaticProps({ params }) {
  const post = await getPost(params.slug)
  return { props: { post } }
}
 
export async function getStaticPaths() {
  const posts = await getAllPosts()
  return {
    paths: posts.map((post) => ({ params: { slug: post.slug } })),
    fallback: false,
  }
}
 
export default function BlogPost({ post }) {
  return <article>{post.title}</article>
}

App Router — dane pobierasz bezpośrednio w komponencie:

Code
// app/blog/[slug]/page.tsx
async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPost(slug)
  return <article>{post.title}</article>
}
 
export default BlogPost
 
export async function generateStaticParams() {
  const posts = await getAllPosts()
  return posts.map((post) => ({ slug: post.slug }))
}

Model pobierania danych w App Router bywa prostszy na poziomie samego kodu, ale dochodzi nowa warstwa decyzji o cache, rewalidacji i granicach między kodem serwerowym, a klienckim. Jeśli interesuje Cię ten temat, możesz zobaczyć więcej o strategiach pobierania danych w artykule o fetch, cache i rewalidacji w Next.js.

2. Layouty w App Router i Pages Router

Pages Router — jeden globalny _app.tsx, opcjonalnie per-page layouts przez pattern z getLayout:

Code
// pages/_app.tsx
export default function App({ Component, pageProps }) {
  const getLayout = Component.getLayout || ((page) => page)
  return getLayout(<Component {...pageProps} />)
}
 
// pages/dashboard.tsx
Dashboard.getLayout = (page) => <DashboardLayout>{page}</DashboardLayout>

App Router — layouty są natywne, zagnieżdżone i zachowują stan:

Code
// app/dashboard/layout.tsx
export default function DashboardLayout({ children }) {
  return (
    <div className="flex">
      <Sidebar />
      <main>{children}</main>
    </div>
  )
}
 
// app/dashboard/settings/layout.tsx
export default function SettingsLayout({ children }) {
  return (
    <div>
      <SettingsNav />
      {children}
    </div>
  )
}

Layouty w App Router mogą zachowywać stan i nie być odtwarzane przy każdej nawigacji w obrębie tego samego drzewa. To ogromna różnica dla , ale tylko wtedy, gdy sensownie zaprojektujesz granice layoutów i nie przeniesiesz zbyt wiele logiki do Client Components.

3. Loading i error states w routingu Next.js

Pages Router — musisz sam zaimplementować loading states, ponieważ error boundaries to dodatkowa konfiguracja:

Code
// pages/dashboard.tsx
import { useState, useEffect } from 'react'
 
export default function Dashboard() {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)
 
  useEffect(() => {
    fetchData()
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false))
  }, [])
 
  if (loading) return <Skeleton />
  if (error) return <ErrorMessage />
  return <DashboardContent data={data} />
}

App Router — konwencja plików obsługuje to automatycznie:

Code
app/dashboard/
├── page.tsx        → główna treść
├── loading.tsx     → pokazywany podczas ładowania
├── error.tsx       → pokazywany przy błędzie
└── not-found.tsx   → pokazywany dla 404
Code
// app/dashboard/loading.tsx
export default function Loading() {
  return <Skeleton />
}
 
// app/dashboard/error.tsx
;('use client')
 
export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Coś poszło nie tak</h2>
      <button onClick={reset}>Spróbuj ponownie</button>
    </div>
  )
}

4. Server Components vs Client Components

W Pages Router komponenty są z natury klienckie. Oznacza to, że nawet po wyrenderowaniu strony na serwerze (SSR/SSG), ich kod JavaScript i tak jest wysyłany do przeglądarki:

Code
// pages/product.tsx
import { formatPrice } from 'heavy-library' // trafia do bundle'a
 
export default function Product({ product }) {
  return <p>{formatPrice(product.price)}</p>
}

App Router — domyślnie Server Components, kod zostaje na serwerze:

Code
// app/product/page.tsx
import { formatPrice } from 'heavy-library' // NIE trafia do bundle'a
 
export default async function Product({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const product = await getProduct(id)
  return <p>{formatPrice(product.price)}</p>
}

To przekłada się na mniejszy JavaScript wysyłany do przeglądarki.

5. Metadata i SEO w App Router i Pages Router

Pages Router — komponent Head lub next/head:

Code
// pages/about.tsx
import Head from 'next/head'
 
export default function About() {
  return (
    <>
      <Head>
        <title>O nas | Moja Strona</title>
        <meta name="description" content="Opis strony" />
        <meta property="og:title" content="O nas" />
      </Head>
      <main>...</main>
    </>
  )
}

App Router — Metadata API z pełnym typowaniem:

Code
// app/about/page.tsx
import { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'O nas | Moja Strona',
  description: 'Opis strony',
  openGraph: {
    title: 'O nas',
  },
}
 
export default function About() {
  return <main>...</main>
}

Metadata API jest czytelniejsze i obsługuje dynamiczne meta tagi bez dodatkowych bibliotek.

Wydajność App Router vs Pages Router

AspektPages RouterApp Router
Bundle sizeWiększy (cały kod do klienta)Mniejszy (Server Components)
Pełna hydratacjaSelektywna hydratacja
StreamingBrakWbudowany z Suspense
Layout persistenceWymaga obejściaNatywne
Initial loadSzybki (SSR/SSG)Szybki + streaming

Problemy App Routera, które warto znać przed wyborem

App Router nie zawsze jest idealnym rozwiązaniem dla każdego zespołu i w każdej sytuacji, dlatego też warto bym rozwinął kilka potencjalnych trudności:

  • Rozróżnienie kodu serwerowego od klienckiego: trudności w odróżnieniu kodu serwerowego od klienta, czyli która część kodu działa na serwerze, a która w przeglądarce. Jest to szczególnie problematyczne, gdy używasz bibliotek, które potrzebują dostępu do funkcji przeglądarki (np. window) lub specjalnych funkcji Reacta (hooków), które działają tylko po stronie klienta.
  • Złożone zarządzanie danymi: Mechanizmy pamięci podręcznej (cache) i odświeżania danych są bardziej zaawansowane niż w Pages Router, ale też bardziej skomplikowane w obsłudze. Samo użycie fetch() do pobierania danych nie gwarantuje, że zawsze będziesz mieć aktualne informacje.
  • Wyzwania w testowaniu: Narzędzia do testowania i same testy wciąż mogą być problematyczne, zwłaszcza przy asynchronicznych komponentach serwerowych. Testy kompleksowe (E2E) są aktualnie bezpieczniejszym wyborem niż próba testowania wszystkiego testami jednostkowymi.
  • Konieczność nauki nowych koncepcji: Zespół musi przyswoić nowe koncepcje, takie jak React Server Components, strumieniowanie danych, akcje serwerowe i nowe sposoby zarządzania pamięcią podręczną. To wymaga czasu i zmiany sposobu myślenia, a to powoduje duży opór zespołu.

Kiedy wybrać Pages Router w projekcie Next.js?

  • Istniejący projekt — migracja dużego projektu to relatywnie duży wysiłek,
  • Proste strony — landing page, portfolio bez zastosowania złożonej logiki,
  • Zespół nie zna App Routera — krzywa uczenia się jest realna,
  • Zależność od bibliotek — niektóre biblioteki nie wspierają jeszcze Server Components,
  • Stabilność — Pages Router jest pewny i bardzo przewidywalny.

Kiedy wybrać App Router w projekcie Next.js?

  • Nowy projekt — w praktyce to domyślny wybór dla większości nowych aplikacji,
  • Złożone layouty — dashboard, panel admina, aplikacja SaaS,
  • SEO i wydajność — łatwiej wykorzystać streaming, Metadata API i nowy model renderowania,
  • Duże ilości danych — Server Components redukują bundle,
  • Streaming — potrzebujesz pokazywać treść progresywnie,

Czy można używać App Router i Pages Router w jednym projekcie?

Tak, jest taka możliwość, by w Next.js używać hybrydowego podejścia — pages/ i app/ mogą współistnieć, co ułatwia stopniową migrację. Właśnie taka stopniowa migracja, może nam oszczędzić sporo złym emocji, a jednocześnie osiągniemy swój cel.

Code
my-project/
├── app/              # nowe strony w App Router
│   ├── dashboard/
│   └── settings/
├── pages/            # legacy strony
│   ├── old-page.tsx
│   └── api/          # API routes (tylko w pages/)

Uwaga! Pamiętaj, że ta sama trasa nie może istnieć w obu folderach (!)

Migracja z Pages Router do App Router

Jeśli masz istniejący projekt, migruj stopniowo:

  1. Utwórz folder app/ i skonfiguruj podstawowy layout.
  2. Zacznij od prostych stron, na "tapetę" weź strony np. about, kontakt, statyczne treści.
  3. Migruj strony z danymi — zamień getStaticProps na komponenty serwerowe async.
  4. Zostaw API routes w pages/api/ albo migruj stopniowo do Route Handlers w app/**/route.ts.
  5. Na końcu migruj te najbardziej złożone strony, czyli dashboardy czy skomplikowane formularze etc.

Nie musisz migrować wszystkiego naraz. Hybrydowe podejście jest w pełni wspierane.

App Router czy Pages Router: moja rekomendacja

Nowy projekt w 2026? Najlepszy wybór to właśnie App Router, ponieważ to kierunek rozwoju Next.js i domyślna ścieżka w aktualnej dokumentacji.

Istniejący projekt? Najlepiej zostań przy Pages Router, jeśli działa i zespół nie potrzebuje funkcji specyficznych dla App Router. Nie migruj na siłę, tylko wtedy, gdy realnie uprości to architekturę albo odblokuje nowe możliwości. Z czasem różnica będzie bardziej widoczna między App Router i Pages Router.

Uczysz się Next.js? Zacznij od App Router i jego modelu routingu, renderowania oraz pobierania danych. Pages Router nadal warto rozumieć, bo masa istniejących projektów nadal go używa, ale nowe rzeczy poznawaj już przede wszystkim w modelu App Router.

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.
Next.js

Często zadawane pytania

Czy Pages Router zostanie usunięty z Next.js?

Nie ma potrzeby zakładać, że działający projekt na Pages Router trzeba natychmiast przepisywać. Pages Router pozostaje wspierany, choć nowe możliwości częściej trafiają najpierw do App Routera.

Co wybrać do nowego projektu w 2026 roku?

Dla większości nowych projektów rozsądniejszym wyborem jest App Router, szczególnie jeśli chcesz korzystać z React Server Components, Server Actions i nowszych wzorców Next.js.

Kiedy nie migrować z Pages Routera?

Nie migruj tylko dlatego, że istnieje nowsza opcja. Migracja ma sens, gdy daje konkretną wartość: lepszą architekturę, wydajność, uproszczenie kodu albo dostęp do funkcji potrzebnych w projekcie.

App Router czy Pages Router — co wybrać w 2026?

Dla nowych projektów App Router jest domyślnym i zalecanym wyborem — to aktywnie rozwijana ścieżka Next.js, wspierana przez Vercel i całą dokumentację frameworka. Dla istniejących projektów działających na Pages Router nie ma presji, aby migrować: router jest nadal wspierany, stabilny i nie zostanie usunięty.

Czy Pages Router zostanie usunięty w przyszłości?

Nie, Vercel wielokrotnie potwierdziło, że Pages Router pozostaje w pełni wspierany, ale nie dostanie nowych funkcji. W miare upływu czasu, App Router będzie uzyskiwał coraz wyraźniejszą przewagę, dlatego rozważenie migracji będzie coraz bardziej na miejscu.

Czy można używać App Router i Pages Router w tym samym projekcie?

Tak, Next.js pozwala na hybrydowe podejście, tj foldery pages/ i app/ mogą współistnieć w jednym projekcie, ale trzeba zwrócić uwagę, by ta sama trasa nie istniała w obu folderach. Poza tym, migracja może być stopniowa i przez to "bezbolesna" nowe strony trafiają do app/, stare pozostają w pages/.

Co to są React Server Components i dlaczego App Router ich używa?

React Server Components (RSC) to komponenty wykonywane wyłącznie na serwerze, a ich kod nie trafia do bundle'a JavaScriptu wysyłanego do przeglądarki - przekłada się to na mniejszy bundle, znacznie szybsze ładowanie i możliwość bezpośredniego dostępu do bazy danych lub API bez dodatkowego endpointu. App Router używa RSC jako domyślnego modelu, co wymaga innego podejścia do granicy server/client.

Ile zajmuje migracja z Pages Router na App Router?

Zależy od rozmiaru projektu. Prosta strona informacyjna — od kilku godzin do jednego dnia. Złożona aplikacja SaaS z wieloma trasami, niestandardowymi layoutami i zależnościami od bibliotek — od kilku dni do kilku tygodni. Migracja jest inkrementalna (nie trzeba robić wszystkiego naraz), ale wymaga przepisania logiki pobierania danych i przebudowy layoutów.

App Router czy Pages Router — co jest szybsze?

App Router ma potencjalnie lepszą wydajność dzięki Server Components (mniejszy bundle JS) i streamingowi HTML z Suspense. Jednak sama zmiana routera nie gwarantuje automatycznej poprawy. Pages Router z dobrym SSG/ISR może być równie szybki dla większości zastosowań. Różnica jest najbardziej odczuwalna w aplikacjach z dużą ilością danych, złożonymi layoutami i potrzebą streamingu.

Czy biblioteki CSS-in-JS działają z App Router?

Część bibliotek CSS-in-JS (styled-components, Emotion) wymaga specjalnej konfiguracji w App Router z powodu Server Components — nie obsługują natywnie trybu serwerowego bez dodatkowych Registry wrapperów. Tailwind CSS, CSS Modules i vanilla CSS działają bez problemów.

O autorze

Maciej Sala

Maciej Sala — Product Manager i Frontend Developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwijam własne projekty.

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną

Biblioteka wiedzy na temat Next.js

Czytaj dalej

Zobacz więcej wpisów
Pages Router do App Router: Migracja w Next.js

Masz działający projekt na Pages Router i chcesz wejść w Server Components, streaming albo Server Actions. Tylko że przepisanie wszystkiego naraz to proszenie się o regresję, więc tego lepiej nie robić. Rozwiązaniem jest Pages i App Router obok siebie w jednym repozytorium i przenoszenie strona po stronie, potem testy i bezpieczne deploye.

Maciej Sala

Maciej Sala

Founder StriveLab

Jak React Server Components wpływają na SEO i performance?

Przez lata React pchał, coraz więcej i więcej pracy do przeglądarki, w efekcie czego mamy większe bundle, hydratacja trwa dłużej, są puste loadingi i strony, które bez JavaScriptu straciły sens. App Router odwraca ten kierunek. React Server Components pozwalają renderować treść na serwerze bez wysyłania całej logiki do klienta, a Server Actions upraszczają formularze i mutacje. To ma znaczenie dla SEO, bo crawler szybciej dostaje HTML. Ma też znaczenie dla biznesu, bo użytkownik szybciej widzi i dostaje to, po co przyszedł.

Maciej Sala

Maciej Sala

Founder StriveLab

Wielojęzyczna strona w Next.js App Router (i18n)

W Pages Router Next.js miał wbudowane wsparcie dla i18n i wystarczyło dodać konfigurację i18n w next.config.js , by framework zarządzał routingiem językowym automatycznie. App Router nie ma tego mechanizmu i właśnie dlatego i18n trzeba zaimplementować samodzielnie lub użyć do tego celu biblioteki. Artykuł jest o zbudowaniu wielojęzycznej strony w Next.js.

Maciej Sala

Maciej Sala

Founder StriveLab