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 + ReactNext.js
Route’lamaReact Router v7Dosya tabanlı (App Router)
RenderYalnızca istemci tarafıSunucu + istemci
Veri çekmeİstemci (useEffect)Sunucu (async component’lar)
APIHarici API gerekirYerleşik API Routes
DağıtımStatik dosyalarVercel 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:

DosyaAmaç
page.tsxBir route tanımlar
layout.tsxSayfaları sarar, navigasyon boyunca kalıcıdır
loading.tsxSayfa yüklenirken gösterilir (Suspense fallback)
error.tsxSayfa hata fırlattığında gösterilir (Error Boundary)
not-found.tsxnotFound() çağrıldığında gösterilir
route.tsAPI 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.

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.

İlgili Yazılar