Next.jsReactApp RouterMigracijaSEODeploymentPerformanse

Kontrolni popis za migraciju na Next.js App Router (s Pages Routera) + česte zamke

Adrijan Omičević··14 min čitanja
Share

# Što ćete naučiti#

Ovaj vodič daje korak-po-korak plan migracije na Next.js App Router s Pages Routera, uz praktičan kontrolni popis koji možete proći zajedno s timom.

Pokrit ćete routing, dohvat podataka, SEO metadatu, deployment razmatranja i rješavanje čestih produkcijskih problema poput iznenađenja s keširanjem, redirecta i dinamičkih ruta.

Ako vam treba osvježenje osnova, krenite s Uvod u Next.js. Ako je vaš tim nov u mentalnom modelu “server-first” UI-ja, pročitajte Vodič za React Server Components. Za SEO kontekst pogledajte Zašto Next.js za SEO.

# Kada migrirati, a kada ostati#

App Router je dugoročni smjer Next.js-a, ali “najnovije” nije uvijek “najbolje za sljedeći sprint”. Koristite ovu matricu odluke kako biste izbjegli polovične migracije koje zapnu na pola puta.

SignalMigrirajte na App Router sadaZa sada ostanite na Pages Routeru
Product roadmapU sljedeća 3 do 6 mjeseci dodajete nove sekcije, dashboarde ili novu marketing stranicuPlanirano je samo manje održavanje i ispravci bugova
Ciljevi performansiTreba vam brži TTFB, streaming, bolja kontrola cachea ili smanjenje client JS-aTrenutne performanse su već prihvatljive i stabilne
Dohvat podatakaŽelite server-first fetching, parallel routes i granularne cache politikeJako se oslanjate na obrasce getServerSideProps koji su čvrsto vezani uz page props
Spremnost timaMožete uložiti u smjernice za code review i testiranje granica server/clientTim nije upoznat s RSC-om i nema vremena za onboarding
InfrastrukturaDeployate na Vercel ili Node runtime koji podržava potrebne značajkeOvisite o custom server postavci ili edge ograničenjima koja kompliciraju paritet
Tolerancija na rizikMožete isporučivati inkrementalno iza feature flagova i mjeritiImate compliance ili release ograničenja zbog kojih su regresije skupe

🎯 Ključna poruka: Migrirajte kada imate poslovni razlog i kapacitet za testiranje i praćenje. App Router je moćan, ali “ship and pray” migracije kažnjava iznenađenjima oko keširanja i renderiranja.

# Plan migracije korak po korak (praktičan kontrolni popis)#

Korak 0: Baseline i inventura#

Prije nego dotaknete kod, zabilježite baseline kako biste mogli dokazati da je migracija pomogla.

Kontrolni popis

  • Zabilježite trenutne Lighthouse rezultate za ključne predloške: homepage, listing, detail page, checkout ili signup.
  • Ako je moguće, pratite Core Web Vitals kod stvarnih korisnika. Google navodi da CWV korelira s bounceom i konverzijom, a poboljšanja LCP-a su često mjerljiva nakon smanjenja client JS-a.
  • Izvezite popis ruta i mapirajte ovisnosti:
    • Statične rute
    • Dinamičke rute i catch-all
    • Redirecti i rewritovi
    • API rute
  • Identificirajte stranice koje koriste:
    • getInitialProps
    • getServerSideProps
    • getStaticProps i ISR
    • next/head
    • next/router
  • Odlučite hoćete li pristup “nove rute prvo u App Routeru” ili strogu migraciju stranicu-po-stranicu.

Isporuka: migracijska tablica koja navodi svaku rutu, njezinu data strategiju i SEO zahtjeve.

Korak 1: Sigurno nadogradite Next.js#

Nemojte istovremeno mijenjati router i raditi nadogradnju major verzije ako kasnite. Prvo nadogradite na modernu stabilnu verziju Next.js-a dok ste još na Pages Routeru, pa tek onda migrirajte.

Kontrolni popis

  • Ažurirajte Next.js i React na podržane verzije za App Router.
  • Uklonite deprecated konfiguraciju i provjerite build upozorenja.
  • Potvrdite da su CI buildovi i produkcijski deploy stabilni.
  • Provjerite da možete pokrenuti next build bez grešaka koje se pojavljuju samo u runtimeu.

⚠️ Upozorenje: Ako i dalje koristite getInitialProps u _app, vjerojatno ćete prenijeti legacy ograničenja u migraciju. Planirajte ga zamijeniti rano ili ga izolirajte na preostali Pages Router dio.

Korak 2: Napravite App Router “ljusku”#

Dodajte app direktorij uz zadržavanje pages funkcionalnosti. Ovo je kralježnica inkrementalnog usvajanja.

Kontrolni popis

  • Kreirajte app/layout.tsx kao globalni layout.
  • Kreirajte app/page.tsx za root rutu ako želite rano migrirati homepage; inače ga ostavite u pages.
  • Dodajte app/not-found.tsx i app/error.tsx za konzistentan UX grešaka.
  • Odlučite kako ćete riješiti globalne providere:
    • Provideri koji se moraju izvršavati u pregledniku pripadaju u client component wrapper.
    • Server-only logika ostaje u server komponentama.

Primjer kostura layouta:

TSX
// app/layout.tsx
export const metadata = {
  title: "Your Site",
  description: "Default description",
};
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

U početku držite layout minimalnim. Providere možete ponovno uvesti nakon što prva ruta radi end-to-end.

Korak 3: Migracija routinga (Pages → App Router)#

Routing u App Routeru je file-system based, ali se konvencije razlikuju.

Pages RouterApp Router
pages/index.tsxapp/page.tsx
pages/about.tsxapp/about/page.tsx
pages/blog/[slug].tsxapp/blog/[slug]/page.tsx
pages/blog/[...slug].tsxapp/blog/[...slug]/page.tsx
_app.tsxapp/layout.tsx plus opcionalni client provider wrapper
_document.tsxu većini slučajeva rješava app/layout.tsx
API rute u pages/apiostavite kako jest ili premjestite u app/api/route.ts

Kontrolni popis

  • Migrirajte rute jednu po jednu, počevši od “low-risk” stranica.
  • Za svaku rutu potvrdite:
    • URL ostaje identičan
    • redirecti se i dalje primjenjuju
    • canonical URL-ovi ostaju ispravni
    • analytics eventi se i dalje okidaju

💡 Savjet: Krenite s rutom koja ima minimalno podataka i nema auth. To vam daje provjeren predložak za layout, metadatu i navigaciju.

Korak 4: Navigacija i parametri#

U App Routeru:

  • next/router zamjenjuje next/navigation.
  • Parametri rute dolaze kroz params prop u page komponentama.
  • Query string se čita kroz searchParams.

Primjer:

TSX
// app/products/[id]/page.tsx
export default function ProductPage({
  params,
  searchParams,
}: {
  params: { id: string };
  searchParams: Record<string, string | string[] | undefined>;
}) {
  const id = params.id;
  const ref = searchParams.ref;
  return null;
}

Kontrolni popis

  • Zamijenite useRouter iz next/router s:
    • useRouter, usePathname, useSearchParams iz next/navigation u client komponentama
  • Izbjegavajte čitanje window.location u server komponentama.
  • Stanje navigacije držite u URL-u kada utječe na SEO ili dijeljenje.

Korak 5: Migracija dohvata podataka#

Ovdje odlazi najviše vremena i ovdje se pojavljuje najviše produkcijskih bugova.

Zamjena za getServerSideProps

Umjesto vraćanja propsa, fetchajte unutar server komponente. Po defaultu je fetch keširan u App Routeru, osim ako to ne isključite.

TSX
// app/users/page.tsx
export default async function UsersPage() {
  const res = await fetch("https://api.example.com/users", { cache: "no-store" });
  const users = await res.json();
  return null;
}

Koristite cache: "no-store" za stvarno dinamične stranice, slično SSR-u. Koristite next: { revalidate: seconds } za ISR-like ponašanje.

Zamjena za getStaticProps i ISR

TSX
// app/blog/page.tsx
export default async function BlogPage() {
  const res = await fetch("https://api.example.com/posts", {
    next: { revalidate: 300 },
  });
  const posts = await res.json();
  return null;
}

Zamjena za getStaticPaths

Koristite generateStaticParams:

TSX
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const res = await fetch("https://api.example.com/slugs", {
    next: { revalidate: 3600 },
  });
  const slugs: string[] = await res.json();
  return slugs.map((slug) => ({ slug }));
}

Kontrolni popis

  • Za svaku migriranu rutu eksplicitno odlučite caching:
    • cache: "no-store" za podatke po requestu
    • revalidate za ISR-style stranice
    • default caching samo kada su podaci zaista statični i sigurni
  • Osigurajte da autentificirane stranice ne keširaju korisnički specifičan sadržaj.
  • Dohvat podataka radite u server komponentama po defaultu, a client komponente uvodite samo kada je potrebno.

⚠️ Upozorenje: Najčešći produkcijski incident u App Routeru je slučajno keširanje personaliziranog sadržaja. Ako stranica čita cookies ili auth stanje, tretirajte je kao dinamičku i provjerite da se response ne dijeli između korisnika.

Korak 6: Granice između Client i Server komponenti#

Dobra migracija smanjuje client JS, ali morate kontrolirati gdje postoje client komponente.

Kontrolni popis

  • Dodajte "use client" samo kada trebate:
    • state
    • effects
    • browser-only API-je
    • event handlere
  • Dohvat podataka držite u server komponentama i prosljeđujte podatke prema dolje.
  • Izbjegavajte uvoz velikih UI biblioteka u server komponente ako na kraju prisile client granice.

Jednostavan obrazac za globalne providere:

TSX
// app/providers.tsx
"use client";
 
export default function Providers({ children }: { children: React.ReactNode }) {
  return children;
}

Zatim to omotajte u app/layout.tsx gdje je potrebno.

Korak 7: SEO i migracija metadate#

App Router koristi Metadata API, koji je strukturiraniji od next/head i pomaže spriječiti dupliciranje tagova.

SEO temaPages Router pristupApp Router pristup
Title i meta descriptionnext/head u straniciexport const metadata ili generateMetadata
Dinamička metadataizračun u komponentigenerateMetadata na temelju params
Canonicalručni tagmetadata alternates.canonical
Open Graphručni meta tagovipolje openGraph
Robotsručni meta tagpolje robots

Primjer dinamičke metadate:

TSX
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: { params: { slug: string } }) {
  const res = await fetch(`https://api.example.com/posts/${params.slug}`, {
    next: { revalidate: 600 },
  });
  const post = await res.json();
 
  return {
    title: post.title,
    description: post.excerpt,
    alternates: {
      canonical: `https://example.com/blog/${params.slug}`,
    },
  };
}

Kontrolni popis

  • Ponovno kreirajte sve kritične tagove:
    • title
    • meta description
    • canonical
    • robots pravila za noindex stranice
    • Open Graph i Twitter kartice
  • Potvrdite da paginacija i filteri pravilno koriste canonical.
  • Osigurajte da structured data ostane prisutna ako koristite JSON-LD.
  • Validirajte s Google Rich Results Test i Search Console URL Inspection.

Za dublje objašnjenje zašto je ovo važno, pogledajte Zašto Next.js za SEO.

ℹ️ Napomena: generateMetadata može fetchati podatke. Tretirajte ga kao dio data strategije rute i primijenite ista cache pravila, inače možete dobiti zastarjele naslove dok se sadržaj stranice ažurira.

Korak 8: Redirecti, rewritovi i Middleware#

Većina redirecta može ostati u next.config.js, ali migracije često uvedu promjene putanja i razlike u trailing slash ponašanju.

Kontrolni popis

  • Izvezite i testirajte redirect pravila u stagingu.
  • Validirajte da se stari URL-ovi i dalje ispravno rješavaju:
    • marketing kampanje
    • backlinkovi
    • indeksirani URL-ovi
  • Ako koristite Middleware:
    • provjerite da ne forsira dinamičko ponašanje na inače statičnim rutama
    • izbjegavajte skupe izračune u Middlewareu

Primjer redirect isječka:

JavaScript
// next.config.js
module.exports = {
  async redirects() {
    return [
      { source: "/old-blog/:slug", destination: "/blog/:slug", permanent: true },
    ];
  },
};

Korak 9: API rute i razmatranja oko Server Actions#

Možete zadržati pages/api dok migrirate UI rute. Prebacite na app/api tek kada to donosi vrijednost.

Kontrolni popis

  • Zadržite stabilne API ugovore tijekom UI migracije.
  • Ako uvodite server actions, potvrdite:
    • CSRF razmatranja
    • auth provjere su na serveru
    • caching ne skriva rezultate mutacija

Ako tim još uči RSC i server-first obrasce, prvo se uskladite oko konvencija. Najbrže je imati kratki interni dokument i link na Vodič za React Server Components.

Korak 10: Deployment i observability#

App Router mijenja runtime ponašanje, posebno oko keširanja. Trebate vidljivost.

Kontrolni popis

  • Provjerite podržava li hosting potrebne runtimove i streaming ponašanje.
  • U stagingu testirajte:
    • cold start performanse
    • cache hit ratio ako je primjenjivo
    • error stranice i 404 ponašanje
  • Dodajte logiranje oko:
    • fetch grešaka
    • neočekivanih notFound slučajeva
    • auth edge caseova
  • Pratite:
    • distribuciju TTFB-a, ne samo prosjek
    • stopu grešaka
    • crawl greške u Search Console nakon lansiranja

💡 Savjet: Radite kontrolirani rollout: migrirajte jednu grupu ruta, deployajte i pratite metrike 24 do 48 sati prije širenja. Problemi App Routera su često ovisni o prometu i neće se vidjeti u lokalnom testiranju.

# Praktičan kontrolni popis migracije (kopirajte i koristite)#

Koristite ovo kao “definition of done” za svaku migriranu rutu.

PodručjeProvjeraKriterij završetka
RoutingParitet URL-aPutanja rute se poklapa sa starom rutom i deep linkovi rade
RoutingDinamički parametriparams i searchParams su točni i tipizirani
Dohvat podatakaCache politikaEksplicitno odabran no-store ili revalidate gdje treba
Dohvat podatakaObrada grešakaPokriveni notFound, error.tsx i stanja kod API grešaka
RSC granicaClient komponenteSamo komponente kojima trebaju browser API-ji koriste "use client"
SEOParitet metadateTitle, description, canonical, OG tagovi odgovaraju starom ponašanju
SEOPravila indeksiranjarobots pravila očuvana za privatne ili “thin” stranice
RedirectiStari URL-oviSvi legacy URL-ovi redirectaju ili služe ekvivalentan sadržaj
PerformanseJS payloadClient bundle ne raste neočekivano
DeploymentParitet okruženjaEnv varovi postoje, runtime je kompatibilan, build prolazi
QAAnalyticsPage view i ključni eventi se i dalje okidaju ispravno
QARegresijski testoviBarem smoke testovi za glavne user flowove

# Rješavanje problema: česte zamke i popravci#

Iznenađenja s keširanjem#

Simptomi

  • Korisnici vide zastario sadržaj nakon objave.
  • Jedan korisnik vidi personalizirane podatke drugog korisnika.
  • Stranica se ažurira tek nakon redeploya.

Uzroci

  • Default fetch caching je nenamjerno korišten.
  • Dijeljeni cache na autentificiranim rutama.
  • Metadata se kešira drugačije od sadržaja stranice.

Kontrolni popis popravaka

  1. 1
    Za korisnički specifične stranice koristite cache: "no-store" i izbjegavajte keširanje izvedenih podataka.
  2. 2
    Ako se sadržaj treba osvježavati svakih N sekundi, postavite next: { revalidate: N } na svim relevantnim fetch pozivima.
  3. 3
    Provjerite da generateMetadata koristi istu caching strategiju kao stranica.
  4. 4
    Auditirajte komponente koje čitaju cookies ili headere i potvrdite da se ruta tretira kao dinamička.

Redirecti i canonicali ruše SEO#

Simptomi

  • Search Console pokazuje duplikate URL-ova ili “alternate page with proper canonical tag.”
  • Organski promet padne nakon migracije.
  • URL-ovi iz kampanja završavaju na neočekivanim stranicama.

Uzroci

  • Nedostaju canonical tagovi nakon uklanjanja next/head.
  • Promjene u trailing slash ponašanju.
  • Redirect pravila nisu kopirana 1:1.

Kontrolni popis popravaka

  1. 1
    Rekreirajte canonical URL-ove kroz metadatu alternates.canonical.
  2. 2
    Provjerite da trailing slash ponašanje odgovara prethodnoj produkciji.
  3. 3
    Usporedite stare i nove popise redirecta i pokrenite automatizirane testove nad top 100 URL-ova.
  4. 4
    Validirajte HTTP status kodove. Koristite 301 za trajno, 302 za privremeno.

Dinamičke rute se ne poklapaju ili vraćaju 404#

Simptomi

  • Dinamičke stranice rade lokalno, ali u produkciji vraćaju 404.
  • Catch-all rute se ponašaju drugačije.
  • generateStaticParams se builda, ali neke putanje nedostaju.

Uzroci

  • Route file je premješten, ali je struktura foldera pogrešna.
  • generateStaticParams ne vraća sve potrebne putanje.
  • Miješanje pages i app stvara nejasna očekivanja oko routinga.

Kontrolni popis popravaka

  1. 1
    Potvrdite strukturu foldera: app/segment/[param]/page.tsx.
  2. 2
    Provjerite da generateStaticParams vraća objekte s ispravnim ključevima.
  3. 3
    Ako su neke putanje zaista dinamičke, oslonite se na runtime renderiranje i postavite caching sukladno tome.
  4. 4
    Dodajte monitoring za neočekivane skokove 404 grešaka nakon releasea.

Napuhavanje client komponenti i regresija performansi#

Simptomi

  • Lighthouse JS execution time raste.
  • Bundleovi postanu veliki nakon migracije.
  • Hydration upozorenja.

Uzroci

  • Previše "use client" datoteka.
  • Uvoz client-only ovisnosti u shared komponentu, što forsira client renderiranje.
  • Nepotrebno premještanje globalnih providera u client scope.

Kontrolni popis popravaka

  1. 1
    Neka server komponente budu default. Dodajte "use client" samo na leaf nodeovima.
  2. 2
    Interaktivne widgete izdvojite u izolirane client komponente.
  3. 3
    Koristite dynamic imports za teški client-only UI.
  4. 4
    Usporedite veličine bundlea prije i poslije te pratite promjene po ruti.

Razlike u deploymentu između staginga i produkcije#

Simptomi

  • Radi u previewu, pada u produkciji.
  • Razlike u edge runtimeu.
  • Build prolazi lokalno, ali pada u CI-ju.

Uzroci

  • Nedostaju env varovi.
  • Različite Node runtime verzije.
  • Cache pravila platforme za hosting se razlikuju od lokalnih očekivanja.

Kontrolni popis popravaka

  1. 1
    Pinajte Node verziju u CI-ju i uskladite je s produkcijskim runtimeom.
  2. 2
    Osigurajte da su env varovi prisutni i za build i za runtime gdje je potrebno.
  3. 3
    Pokrećite next build u CI-ju s istim flagovima kao u produkciji.
  4. 4
    Testirajte ponašanje na cold deployu, ne samo hot reload.

# Ključne poruke#

  • Migrirajte inkrementalno tako da Pages Router i App Router rade paralelno, rutu po rutu, uz jasne “done” kriterije.
  • Tretirajte caching kao zadatak prve klase: eksplicitno odaberite no-store ili revalidate za svaku rutu i svaki metadata fetch.
  • Ponovno izgradite SEO preko Metadata API-ja, uključujući canonicale, robots pravila i Open Graph, zatim validirajte u Search Console.
  • Zamijenite next/router s next/navigation i oslonite se na params i searchParams umjesto ručnog parsiranja URL-a.
  • Očekujte da će se većina problema u produkciji vrtjeti oko keširanja, redirecta i dinamičkih ruta, i pripremite automatizirane URL testove plus monitoring.

# Zaključak#

Uspješna migracija na Next.js App Router manje je pitanje premještanja datoteka, a više promišljanja dohvata podataka, keširanja i SEO-a kao namjernih odluka po ruti.

Ako želite da Samioda pregleda vaš plan migracije, auditira caching i SEO paritet ili odradi inkrementalni rollout uz minimalan rizik, kontaktirajte nas i pomoći ćemo vam isporučiti App Router nadogradnju uz mjerljiva poboljšanja performansi i stabilnosti.

FAQ

Share
A
Adrijan OmičevićSamioda Team
All articles →

Trebate pomoć s projektom?

Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.