React temellerini öğrendikten sonra sıradaki adım Next.js: üretim React uygulamaları için tasarlanmış framework.
Next.js Nedir?
Next.js, Vercel tarafından geliştirilen bir React framework’ü. React’in üzerine şunları ekliyor:
- Dosya tabanlı route’lama: Router yapılandırmasına gerek yok
- Server Components: React’i sunucuda çalıştırır
- Server Actions: İstemciden sunucu fonksiyonlarını çağırır
- Optimize edilmiş görsel, font ve script yükleme
- API Routes: Aynı proje içinde bir backend API’si kurar
react.dev, üretim React uygulamaları için Next.js gibi bir framework kullanmayı öneriyor.
Next.js mi, React (Vite) mi?
| Vite + React | Next.js | |
|---|---|---|
| Route’lama | React Router v7 | Dosya tabanlı (App Router) |
| Render | Yalnızca istemci tarafı | Sunucu + istemci |
| Veri çekme | İstemci (useEffect) | Sunucu (async component’lar) |
| API | Harici API gerekir | Yerleşik API Routes |
| Dağıtım | Statik dosyalar | Vercel ya da Node.js sunucusu |
SPA’lar ve araçlar için Vite kullanın. Web siteleri, bloglar ve full-stack uygulamalar için Next.js kullanın.
Next.js 15 Uygulaması Oluşturma
npx create-next-app@latest myapp
Şu soruları göreceksiniz:
✔ Would you like to use TypeScript? Yes
✔ Would you like to use ESLint? Yes
✔ Would you like to use Tailwind CSS? Yes
✔ Would you like your code inside a `src/` directory? Yes
✔ Would you like to use App Router? Yes ← Önemli: Yes seçin
✔ Would you like to use Turbopack for next dev? Yes
✔ Would you like to customize the import alias? No
Her zaman App Router‘ı seçin. Pages Router eski sistem; hâlâ destekleniyor ama yeni projeler için önerilmiyor.
Geliştirme sunucusunu başlatın:
cd myapp
npm run dev
http://localhost:3000 adresini açın. Turbopack, Next.js 15’te geliştirme sunucusunu çok hızlı hale getiriyor.
App Router: Klasör Yapısı
src/
└── app/
├── layout.tsx ← Kök layout (tüm sayfaları sarar)
├── page.tsx ← Ana sayfa (route: /)
├── globals.css ← Global CSS
├── about/
│ └── page.tsx ← Hakkımızda sayfası (route: /about)
├── blog/
│ ├── page.tsx ← Blog listesi (route: /blog)
│ └── [slug]/
│ └── page.tsx ← Blog yazısı (route: /blog/my-post)
└── api/
└── hello/
└── route.ts ← API route (route: /api/hello)
Klasör yapısı, route yapısının kendisi. Ekstra yapılandırma gerekmiyor.
Dosya Kuralları
Next.js’te özel davranışlara sahip özel dosya isimleri var:
| Dosya | Amaç |
|---|---|
page.tsx | Bir route tanımlar |
layout.tsx | Sayfaları sarar, navigasyon boyunca kalıcıdır |
loading.tsx | Sayfa yüklenirken gösterilir (Suspense fallback) |
error.tsx | Sayfa hata fırlattığında gösterilir (Error Boundary) |
not-found.tsx | notFound() çağrıldığında gösterilir |
route.ts | API endpoint’i (JSX yok) |
İlk Sayfanız
// src/app/page.tsx
export default function HomePage() {
return (
<main className="container mx-auto px-4 py-8">
<h1 className="text-4xl font-bold">Welcome</h1>
<p className="mt-4 text-gray-600">This is the home page.</p>
</main>
);
}
Fonksiyon bir default export olmalı. Dosyanın adı page.tsx olmalı.
Layout’lar
Layout’lar sayfaları sarar ve navigasyon boyunca kalıcı kalır. app/layout.tsx içindeki kök layout her sayfayı sarar:
// src/app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import Link from "next/link";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "My App",
description: "Built with Next.js 15",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<header className="border-b py-4 px-6">
<nav>
<Link href="/">Home</Link>
<Link href="/about" className="ml-4">About</Link>
</nav>
</header>
<main>{children}</main>
<footer className="border-t py-4 px-6 text-center text-gray-500">
© 2026 My App
</footer>
</body>
</html>
);
}
İç içe layout’lar yalnızca kendi bölümlerini sarar. Belirli bir bölüm için layout oluşturun:
// src/app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex">
<aside className="w-64 border-r p-4">
{/* Kenar çubuğu: tüm dashboard sayfalarında görünür */}
<nav>...</nav>
</aside>
<div className="flex-1 p-6">{children}</div>
</div>
);
}
Dinamik Route’lar
Dinamik segmentler için köşeli parantez [param] kullanın:
// src/app/blog/[slug]/page.tsx
// Eşleşenler: /blog/my-first-post, /blog/react-tutorial, vb.
interface PageProps {
params: Promise<{ slug: string }>;
}
export default async function BlogPostPage({ params }: PageProps) {
// Next.js 15'te params bir Promise; await edilmeli
const { slug } = await params;
const post = await fetchPost(slug);
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
Önemli: Next.js 15’te params ve searchParams artık Promise. Bunları await etmeniz gerekiyor.
Çoklu Dinamik Segmentler
app/
└── users/
└── [userId]/
└── posts/
└── [postId]/
└── page.tsx ← /users/123/posts/456
interface PageProps {
params: Promise<{ userId: string; postId: string }>;
}
export default async function PostPage({ params }: PageProps) {
const { userId, postId } = await params;
// ...
}
Catch-All Route’lar
[...slug], birden fazla path segmentini eşleştirir:
// app/docs/[...slug]/page.tsx
// Eşleşenler: /docs/intro, /docs/api/reference, /docs/a/b/c
interface PageProps {
params: Promise<{ slug: string[] }>;
}
export default async function DocsPage({ params }: PageProps) {
const { slug } = await params; // ["api", "reference"]
// ...
}
[[...slug]] (çift köşeli parantez), üst path’i segment olmadan da (/docs) eşleştirir.
Route Grupları
Parantez kullanarak route’ları URL’yi etkilemeden gruplayın:
app/
├── (marketing)/
│ ├── page.tsx ← /
│ ├── about/page.tsx ← /about
│ └── layout.tsx ← Sadece marketing sayfaları için layout
└── (app)/
├── dashboard/page.tsx ← /dashboard
└── layout.tsx ← Uygulama sayfaları için farklı layout
(marketing) ve (app), URL’de görünmüyor; yalnızca organizasyon ve ayrı layout’lar için kullanılıyor.
Link ile Navigasyon
Navigasyon için <a> yerine next/link kullanın:
import Link from "next/link";
function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
);
}
Link, bağlantı verilen sayfayı arka planda önceden yüklüyor (prefetch); navigasyon anlık hissettiriyor.
Metadata
Metadata API ile SEO metadata ekleyin:
// Statik metadata
export const metadata = {
title: "About Us",
description: "Learn about our team.",
};
// Dinamik metadata (async)
export async function generateMetadata({ params }: PageProps) {
const { slug } = await params;
const post = await fetchPost(slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
images: [post.imageUrl],
},
};
}
Türkiye’den Yayınlarken Barındırma Notu
Next.js’i geliştiren şirket olan Vercel, projeyi Vercel’e deploy etmeyi son derece kolaylaştırıyor: git push sonrası otomatik build ve global CDN dağıtımı. Ancak iki nokta akılda tutulmalı. Birincisi, Vercel’in ücretsiz (Hobby) katmanı kişisel projeler için yeterli olsa da, ticari kullanım ve daha yüksek trafik Pro plana geçmeyi gerektiriyor ve faturalandırma dolar üzerinden; kartınızın yurt dışı işlem ücretini ve kur riskini hesaba katmalısınız. İkincisi, Vercel’in fonksiyon bölgelerinin çoğu ABD ve Batı Avrupa’da; Türkiye’den erişimde statik sayfalar CDN sayesinde hızlı açılsa da, sunucu tarafında çalışan (Server Actions, API Routes gibi) dinamik kısımlar için gecikme (latency) hissedilebilir.
Bu yüzden ağırlıklı olarak Türkiye’deki kullanıcılara hizmet veren bir proje için pratik iki seçenek var: Vercel’i kullanmaya devam edip dinamik işlemleri mümkün olduğunca azaltmak (statik üretim ve önbellekleme ile), ya da uygulamayı Node.js sunucusu olarak paketleyip Avrupa’ya coğrafi olarak daha yakın bir VPS’e (örneğin bir Docker konteyneri içinde) kendiniz deploy etmek. İkinci yol daha fazla operasyonel yük getiriyor ama Vercel’in dolar bazlı ücretlendirmesinden bağımsızlaşmak isteyen ekipler için makul bir alternatif. Konteyner tabanlı bir deploy’a başlamak için Docker Nasıl Kurulur? yazısına bakabilirsiniz.