Next.js vam daje sve što je potrebno za tehnički SEO, ali gotovo ništa od toga nije uključeno podrazumevano. Ovo je lista koju prođem na svakom App Router projektu, otprilike po redosledu uticaja.
1. Renderujte važan sadržaj na serveru
Pretraživači mogu da izvršavaju JavaScript, ali HTML renderovan na serveru indeksiraju brže i pouzdanije. U App Routeru su Server Components podrazumevane — držite naslove, tekst i linkove u njima, a Client Components koristite za interakciju, ne za sadržaj.
Brz test: otvorite stranicu sa isključenim JavaScriptom ili pokrenite curl https://yoursite.com/page. Ako glavnog teksta nema u odgovoru, nema ga ni u prvom krugu indeksiranja.
2. Podesite metadataBase i šablon naslova
U glavnom layoutu:
import type { Metadata } from 'next'
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: {
default: 'Example Studio — Web Design and Development',
template: '%s — Example Studio',
},
description: 'Websites and products for small teams: design, development and launch.',
openGraph: { siteName: 'Example Studio', type: 'website' },
}metadataBase pretvara relativne URL-ove (kanonske, Open Graph slike) u apsolutne. Zahvaljujući šablonu, podstranice postavljaju samo svoj deo naslova.
3. Jedinstveni naslovi i opisi za svaku stranicu
Svaka stranica koja treba da se indeksira mora da ima sopstveni <title> (oko 50–60 karaktera, ključna reč pri početku) i meta opis (oko 150–160 karaktera, napisan tako da ljudi požele da kliknu). Za dinamičke stranice koristite generateMetadata:
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPost(slug)
if (!post) return {}
return {
title: post.title,
description: post.excerpt,
alternates: { canonical: `/blog/${post.slug}` },
openGraph: {
type: 'article',
publishedTime: post.date,
images: [{ url: post.cover, width: 1200, height: 630 }],
},
}
}4. Kanonski URL-ovi
Podesite alternates.canonical na svakoj stranici. Štiti vas od duplikata koje stvaraju parametri upita (?utm_source=...), kose crte na kraju i alternativni domeni. Izaberite jedan oblik — sa ili bez www, sa ili bez kose crte na kraju — i ostale preusmerite na njega na nivou hostinga.
5. Sitemap
app/sitemap.ts generiše /sitemap.xml, i to radi i kod statičkog izvoza:
import type { MetadataRoute } from 'next'
import { getAllPosts } from '@/lib/blog'
export const dynamic = 'force-static'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const base = 'https://example.com'
const posts = await getAllPosts()
return [
{ url: base, changeFrequency: 'monthly', priority: 1 },
...posts.map((post) => ({
url: `${base}/blog/${post.slug}`,
lastModified: post.date,
changeFrequency: 'yearly' as const,
priority: 0.7,
})),
]
}Prijavite ga jednom u Google Search Console i Bing Webmaster Tools.
6. robots.txt
import type { MetadataRoute } from 'next'
export const dynamic = 'force-static'
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: '*', allow: '/' },
sitemap: 'https://example.com/sitemap.xml',
}
}Ne koristite robots.txt da biste sakrili stranice iz indeksa — blokirana stranica i dalje može biti indeksirana preko linkova. Umesto toga koristite robots: { index: false } u metapodacima stranice.
7. Strukturirani podaci (JSON-LD)
Strukturirani podaci pomažu pretraživačima da razumeju šta stranica jeste. Za članak, renderujte script tag na stranici:
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
datePublished: post.date,
image: `https://example.com${post.cover}`,
author: { '@type': 'Person', name: 'Jane Doe', url: 'https://example.com' },
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
/>
)Korisni tipovi za mala preduzeća: Organization ili Person na početnoj stranici, BlogPosting za članke, BreadcrumbList za dublje stranice, Product za prodavnicu. Proverite ih Google-ovim alatom Rich Results Test.
8. Open Graph slike
Linkovi podeljeni na LinkedInu, X-u, Slacku i u aplikacijama za poruke koriste Open Graph oznake. Dajte svakoj stranici sliku od 1200×630 piksela. Možete dodati statički opengraph-image.png pored stranice ili je generisati pomoću ImageResponse u opengraph-image.tsx (kod statičkog izvoza generiše se tokom build-a, pa ne može da zavisi od zahteva).
9. Višejezični sajtovi: pravi URL-ovi i hreflang
Svaki jezik mora da ima svoj URL, inače će pretraživači videti samo jedan. Menjanje jezika na klijentu preko localStorage je u redu za posetioce, ali je nevidljivo za Google. Koristite segment za jezik — app/[lang]/... — i navedite alternative:
alternates: {
canonical: '/en/blog/my-post',
languages: {
en: '/en/blog/my-post',
'zh-CN': '/zh/blog/my-post',
'sr-Latn': '/sr/blog/my-post',
'x-default': '/en/blog/my-post',
},
}Svaka jezička verzija treba da navede sve ostale, uključujući i sebe.
10. Interni linkovi i naslovi
- Jedan
<h1>po stranici, zatim<h2>/<h3>redom. Naslovi su struktura, ne veličina fonta. - Povezujte srodne stranice opisnim tekstom linka („vodič za statički izvoz", ne „kliknite ovde"). Koristite
<Link>da bi linkovi bili pravi<a href>elementi. - Važne stranice držite na najviše tri klika od početne.
11. Core Web Vitals
Brzina je signal za rangiranje, a još važnije — signal za konverziju. Merite pomoću PageSpeed Insights (terenski podaci dolaze od stvarnih Chrome korisnika) i ciljajte LCP ≤ 2,5 s, INP ≤ 200 ms i CLS ≤ 0,1. Uobičajeni krivci u App Routeru: prevelika naslovna slika, previše JavaScripta na klijentu i pomeranje rasporeda zbog fontova ili slika bez dimenzija. Ako je vaš sajt pun animacija, pogledajte Core Web Vitals za animirane sajtove.
12. Slike
- Opisan
alttekst za sadržajne slike; prazanalt=""za dekorativne. - Eksplicitni
width/heightiliaspect-ratioda se spreči pomeranje rasporeda. - Moderni formati (AVIF, WebP) i razumne veličine.
- Opisni nazivi fajlova:
nextjs-sitemap-example.png, neIMG_2041.png.
13. 404 i preusmerenja
Za nepostojeće stranice vratite pravi 404 (notFound() u App Routeru). Kada premeštate ili preimenujete stranice, dodajte 301 preusmerenje sa starog URL-a — kod statičkog izvoza to je pravilo u _redirects na hostingu.
Kratka verzija
- Sadržaj u Server Components
-
metadataBasei šablon naslova u glavnom layoutu - Jedinstven naslov, opis i kanonski URL na svakoj stranici
-
sitemap.tsirobots.ts, sitemap prijavljen - JSON-LD za članke, organizaciju, breadcrumbs
- Open Graph slika na svakoj stranici
- Jedan URL po jeziku, uz hreflang
- Logični naslovi i opisni interni linkovi
- Core Web Vitals u zelenom
- Pravi 404 i 301 za premeštene stranice
Pravite statički sajt? Pročitajte vodič za Next.js statički izvoz za delove koji rade drugačije bez servera.

