Next.js SEO arhitektura za organski rast
Next.js SEO počinje od arhitekture. Okvir već daje HTML sa servera, Metadata API, sitemap i optimizaciju slika, a na vama je da ih koristite dosledno, na svakoj stranici. Ovaj vodič pokazuje kako da od toga napravite brzu aplikaciju koju pretraživači lako čitaju i koja posetioce pretvara u korisnike.
Šest ključnih Next.js SEO funkcija
Sve što je potrebno za SEO već je ugrađeno u Next.js App Router. Razliku pravi doslednost: iste provere na svakoj stranici.
Metadata API
Naslov, opis, canonical i Open Graph zadajete kroz Metadata API: objektom metadata na statičnim stranicama, a funkcijom generateMetadata na dinamičkim.
- Prednost: tipovi se proveravaju pri build-u, a tagovi stižu u HTML-u sa servera
Statičko generisanje
Stranice se renderuju unapred, pri build-u, i služe se iz keša, bez čekanja na server.
- Prednost: kratko vreme do prvog bajta (TTFB) i stabilan LCP
Dinamički sitemap
Fajl app/sitemap.ts pravi sitemap iz istih podataka iz kojih nastaju i stranice.
- Prednost: sitemap je uvek ažuran, bez ručnog održavanja
Optimizacija slika
Komponenta Image sama optimizuje slike: bira pravu veličinu i moderan format (WebP ili AVIF), a slike van ekrana učitava tek kada zatrebaju.
- Prednost: brži LCP, prave dimenzije, moderni formati
Strukturisani podaci
JSON-LD u tagu <script type="application/ld+json"> govori pretraživaču ko ste i šta je na stranici, a neki tipovi daju i proširen prikaz u rezultatima.
- Prednost: pretraživač tačnije razume sadržaj
Robots.txt
U fajlu app/robots.ts određujete kuda botovi pretraživača smeju da prolaze.
- Prednost: botovi ne troše vreme na admin i privatne stranice. robots.txt ne skriva stranicu iz rezultata – za to služi noindex.
Kod spreman za kopiranje
Četiri osnovna dela SEO arhitekture u Next.js App Router-u: metapodaci, sitemap, robots.txt i strukturisani podaci. Zamenite yoursite.com svojim domenom i tekstove svojim sadržajem.
// app/page.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Your Page Title — Brand Name',
description: 'Compelling description 150-160 characters that includes target keywords and value proposition.',
openGraph: {
title: 'Your Page Title',
description: 'Description for social sharing',
url: 'https://yoursite.com/page',
siteName: 'Your Site Name',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'Your Page Title',
description: 'Description for Twitter',
},
alternates: {
canonical: 'https://yoursite.com/page',
},
}
// app/sitemap.ts
import type { MetadataRoute } from 'next'
// lastModified = datum kada se sadržaj zaista promenio, a ne new Date() pri svakom build-u.
// Google ignoriše changeFrequency i priority, pa ih ne navodimo.
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://yoursite.com',
lastModified: new Date('2026-11-02'),
},
{
url: 'https://yoursite.com/about',
lastModified: new Date('2026-06-15'),
},
// Dodajte sve svoje rute
]
}
// app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: '/admin/',
},
sitemap: 'https://yoursite.com/sitemap.xml',
}
}
// components/StructuredData.tsx
export function OrganizationSchema() {
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Your Company',
url: 'https://yoursite.com',
logo: 'https://yoursite.com/logo.png',
description: 'Company description',
sameAs: [
'https://x.com/yourcompany',
'https://www.linkedin.com/company/yourcompany',
],
}
// Zamena znaka < sprečava ubacivanje HTML-a kroz podatke (preporuka iz Next.js dokumentacije)
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(schema).replace(/</g, '\\u003c'),
}}
/>
)
}Optimizujte Core Web Vitals
Core Web Vitals su deo Google-ovih signala za rangiranje. Slab sadržaj ne nadoknađuju, ali brz sajt zadržava posetioce. Google ih meri na stvarnim posetama: stranica prolazi kada je bar 75% poseta u granicama navedenim ispod. Next.js ima alat za svaku od tri metrike.
LCP (Largest Contentful Paint) – cilj: do 2,5 sekunde
- Glavnu sliku na vrhu stranice prikažite komponentom Image sa fetchPriority="high", da se ne učitava lenjo (prop priority je u Next.js 16 zamenjen propom preload)
- Fontove učitavajte preko next/font: hostuju se sa vašeg domena i učitavaju unapred
- Sadržaj na vrhu stranice renderujte na serveru
- Gde god možete, koristite statičko generisanje
INP (Interaction to Next Paint) – cilj: do 200 milisekundi
- Delove bez interakcije ostavite kao Server Components, da manje JavaScript-a stigne u pregledač
- Teške komponente učitavajte tek kada zatrebaju (next/dynamic)
- Skupe izmene stanja obeležite sa useTransition, da odgovor na klik ne čeka
- Duge zadatke delite na kraće, da ne blokiraju glavnu nit
- Skripte drugih servisa učitavajte preko next/script, sa strategijom afterInteractive ili lazyOnload
CLS (Cumulative Layout Shift) – cilj: do 0,1
- Slikama uvek zadajte dimenzije (width i height, ili fill u okviru fiksne veličine)
- Rezervišite prostor za sadržaj koji stiže kasnije: banere, ugrađene video-snimke, reklame
- Ne ubacujte sadržaj iznad onoga što je već prikazano
- next/font podešava rezervni font tako da se tekst ne pomeri kada se učita pravi
INP je 12. marta 2024. zamenio FID (First Input Delay). FID je merio samo kašnjenje prve interakcije, a INP prati odziv svih klikova, dodira i unosa sa tastature tokom posete, pa je stroži.
Dinamičke rute, jezici i srpska slova
generateStaticParams pravi statičke stranice od dinamičkih ruta, a generateMetadata daje svakoj stranici njen canonical i hreflang. Od Next.js 15 params je Promise, pa ga čekate sa await. Za sajt na srpskom dodajte latin-ext podskup fonta i oznaku sr-Latn. Tako radi i ovaj sajt: srpski je na „/“, a engleski na „/en“.
// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { getAllPosts, getPost } from '@/lib/posts'
// Sve objave se renderuju unapred, pri build-u
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({ slug: post.slug }))
}
// Svaka stranica dobija svoj naslov, opis, canonical i hreflang
export async function generateMetadata(
{ params }: { params: Promise<{ slug: string }> },
): Promise<Metadata> {
const { slug } = await params
const post = await getPost(slug)
if (!post) return {}
return {
title: post.title,
description: post.excerpt,
alternates: {
canonical: `https://yoursite.com/blog/${slug}`,
languages: {
sr: `https://yoursite.com/blog/${slug}`,
en: `https://yoursite.com/en/blog/${post.enSlug}`,
'x-default': `https://yoursite.com/en/blog/${post.enSlug}`,
},
},
}
}
export default async function Page(
{ params }: { params: Promise<{ slug: string }> },
) {
const { slug } = await params
const post = await getPost(slug)
if (!post) notFound()
return <article>{post.title}</article>
}
// app/layout.tsx
import { Inter } from 'next/font/google'
// latin-ext dodaje č, ć, š, ž i đ
const inter = Inter({ subsets: ['latin', 'latin-ext'], display: 'swap' })
// <html lang> je u root layout-u. Za dva jezika napravite po jedan root layout
// za svaki jezik (route grupe, npr. app/(sr) i app/en) ili segment [lang].
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="sr-Latn" className={inter.className}>
<body>{children}</body>
</html>
)
}
// lib/format.ts
// Sama oznaka „sr“ daje nazive meseci na ćirilici; za latinicu: sr-Latn-RS
export const formatDate = (date: Date) =>
new Intl.DateTimeFormat('sr-Latn-RS', { day: 'numeric', month: 'long', year: 'numeric' }).format(date)Pitanja o Next.js SEO-u
App Router ili Pages Router – šta je bolje za SEO?
Oba daju HTML sa servera, pa i sa Pages Router-om sajt može dobro da se rangira. App Router ipak ima prednost: Metadata API, fajlove sitemap.ts i robots.ts, Server Components koji šalju manje JavaScript-a u pregledač i streaming. Next.js se razvija u tom pravcu, pa nove projekte počnite na App Router-u.
Kako da dinamičke rute u Next.js-u budu dobre za SEO?
Funkcijom generateStaticParams renderujte dinamičke rute unapred, pri build-u. Dobijate statičke stranice, a zadržavate dinamičko rutiranje. Za sadržaj koji se često menja, opcijom revalidate (ili funkcijom cacheLife, ako u Next.js 16 koristite Cache Components) određujete koliko često se stranica ponovo generiše.
Da li mi za SEO treba renderovanje na serveru (SSR)?
Ne uvek. Pretraživaču je važno da HTML već sadrži tekst, a to daju i SSR i statičko generisanje. Statička stranica se služi iz keša, pa server brže odgovara. SSR koristite kada stranica mora da prikaže podatke u trenutku zahteva, na primer trenutno stanje zaliha ili vodostaja. Većina marketinških stranica treba da bude statička.
Kako da dodam strukturisane podatke u Next.js?
Napravite komponentu koja renderuje <script type="application/ld+json"> sa JSON-LD podacima i ubacite je u stranicu ili layout. Znak < u podacima zamenite sa \u003c, kao u primeru iznad. Koristite schema.org tipove koji odgovaraju sadržaju (Organization, Article, Product i slično) i proverite ih alatom Rich Results Test.
Može li Next.js da podrži veliki sitemap?
Može. Sitemap generišite iz baze ili CMS-a. Jedan sitemap fajl može da sadrži najviše 50.000 adresa i 50 MB, pa veći sajt podelite na više fajlova funkcijom generateSitemaps i sve ih navedite u robots.txt ili u sitemap indeksu.
Kako da optimizujem Core Web Vitals u Next.js-u?
Koristite komponentu Image, statičko generisanje, next/font i next/script, a teške delove učitavajte tek kada zatrebaju. Next.js većinu optimizacija radi sam ako koristite njegove ugrađene komponente. Rezultate pratite u PageSpeed Insights-u i u izveštaju Core Web Vitals u Search Console-u, a podatke sa stvarnih poseta možete da prikupljate i sami, hookom useReportWebVitals.
Kako da podesim hreflang za srpsku i englesku verziju?
U generateMetadata navedite alternates.languages sa adresama obe verzije i x-default, a svaka verzija neka ima svoj canonical. Veze moraju da budu obostrane: srpska stranica navodi englesku i obrnuto, inače Google ignoriše hreflang. U <html lang> stavite sr-Latn za srpsku latinicu, a datume formatirajte preko Intl sa oznakom sr-Latn-RS. Primer je u kodu iznad.
Next.js SEO kontrolna lista
Pre objave prođite kroz listu i proverite da li je Next.js aplikacija spremna za pretraživače.
- Metadata API na svim stranicama
- metadataBase u root layout-u, da canonical i Open Graph slike dobiju pune adrese
- Jedinstven naslov i opis za svaku stranicu
- Open Graph i Twitter Card metapodaci
- Dinamički sitemap.ts sa tačnim datumom izmene
- Pravilno podešen robots.txt
- Strukturisani podaci (JSON-LD) na stranicama kojima odgovaraju
- Komponenta Image za sve slike
- Statičko generisanje za sve stranice gde je moguće
- Dinamičke rute sa generateStaticParams
- canonical i hreflang za svaku jezičku verziju (ako je sajt višejezičan)
- Font sa latin-ext podskupom ako je sadržaj na srpskom
- Interni linkovi između srodnih stranica
- Pravilna hijerarhija naslova (jedan H1)
- Alt tekst na svim slikama
- Core Web Vitals u zelenom (LCP, INP, CLS)
- Prikaz na mobilnom proveren
- HTTPS uključen
Još SEO vodiča i primera
SEO optimizacija sajta
Principi SEO arhitekture koji važe za svaki okvir, ugrađeni od prvog dana.
Tehnički SEO za SaaS
SEO strategije za SaaS proizvode i aplikacije iza prijave.
Kako poboljšati SEO uz AI
Kako da uz AI ubrzate SEO optimizaciju.
Vodostaj.rs
Sa React SPA na Next.js: 2,6 miliona prikaza i 60.595 organskih klikova od pokretanja do 31. jula 2026.
Treba vam Next.js aplikacija spremna za SEO?
Pravimo Next.js aplikacije sa SEO arhitekturom od prvog dana: metapodaci, strukturisani podaci, sitemap i brzina su deo izrade, a ne naknadna popravka.
Izrada web aplikacija