İçeriğe geç
nextjs

Next.js App Router: Dosya Tabanlı Routing Sistemi

Tarık Tunç
Next.js App Router: Dosya Tabanlı Routing Sistemi

Next.js App Router: Dosya Tabanlı Routing Sistemi

Next.js 13 ile tanıtılan ve Next.js 14-15 ile olgunlaşan App Router, React Server Components üzerine inşa edilmiş modern bir routing sistemidir. Dosya sistemi tabanlı bu yaklaşım, klasör yapısını doğrudan URL yapısına eşleyerek sezgisel ve güçlü bir routing deneyimi sunar. Bu rehberde App Router'ın tüm detaylarını inceleyeceğiz.

App Router vs Pages Router

Next.js iki farklı routing sistemi sunar. Yeni projelerde App Router kullanılması önerilir:

Özellik App Router Pages Router (Legacy)
Server Components ✅ Varsayılan ❌ Yok
Nested Layouts ✅ Yerleşik ❌ Manuel
Loading UI ✅ loading.tsx ❌ Manuel
Error Handling ✅ error.tsx ❌ _error.tsx
Streaming ✅ Destekleniyor ❌ Sınırlı

Dosya Tabanlı Routing Temelleri

App Router'da her klasör bir route segmenti temsil eder ve page.tsx dosyası o route'u erişilebilir kılar:

src/app/
├── page.tsx                    # → /
├── about/
│   └── page.tsx                # → /about
├── blog/
│   ├── page.tsx                # → /blog
│   └── [slug]/
│       └── page.tsx            # → /blog/:slug
├── dashboard/
│   ├── layout.tsx              # Dashboard layout
│   ├── page.tsx                # → /dashboard
│   ├── settings/
│   │   └── page.tsx            # → /dashboard/settings
│   └── analytics/
│       └── page.tsx            # → /dashboard/analytics
└── (marketing)/
    ├── pricing/
    │   └── page.tsx            # → /pricing
    └── features/
        └── page.tsx            # → /features

Özel Dosyalar

App Router, belirli amaçlar için özel dosya adları tanımlar. Bu dosyalar routing davranışını ve UI yapısını kontrol eder:

  • page.tsx: Route'un UI'ını tanımlar, sayfayı erişilebilir kılar
  • layout.tsx: Paylaşılan layout, alt route'ları sarar
  • loading.tsx: Yükleme UI'ı, Suspense boundary oluşturur
  • error.tsx: Hata UI'ı, Error boundary oluşturur
  • not-found.tsx: 404 sayfası
  • template.tsx: Layout benzeri ama her navigasyonda yeniden render edilir
  • default.tsx: Parallel routes için fallback

Layout'lar ve İç İçe Layout'lar

Layout'lar, birden fazla sayfa arasında paylaşılan UI bileşenleridir. Alt route'lar arasında gezinirken layout yeniden render edilmez:

// src/app/dashboard/layout.tsx
import { Sidebar } from '@/components/Sidebar';

export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex">
      <Sidebar />
      <main className="flex-1 p-6">
        {children}
      </main>
    </div>
  );
}

// src/app/dashboard/page.tsx
export default function DashboardPage() {
  return <h1>Dashboard Ana Sayfa</h1>;
}

// src/app/dashboard/settings/page.tsx
export default function SettingsPage() {
  return <h1>Ayarlar</h1>;
}
İpucu: Layout'lar state'lerini korur ve yeniden render edilmez. Eğer her sayfa değişiminde yeniden render istiyorsanız template.tsx kullanın.

Route Groups

Parantez içinde yazılan klasörler route group olarak adlandırılır ve URL yapısını etkilemez. Organize etmek ve farklı layout'lar uygulamak için kullanılır:

src/app/
├── (auth)/
│   ├── layout.tsx          # Auth sayfaları için özel layout
│   ├── login/
│   │   └── page.tsx        # → /login
│   └── register/
│       └── page.tsx        # → /register
├── (marketing)/
│   ├── layout.tsx          # Marketing sayfaları için özel layout
│   ├── about/
│   │   └── page.tsx        # → /about
│   └── pricing/
│       └── page.tsx        # → /pricing
└── (dashboard)/
    ├── layout.tsx          # Dashboard için özel layout
    └── dashboard/
        └── page.tsx        # → /dashboard

Next.js, client-side navigasyon için Link bileşeni sunar. Bu bileşen sayfaları prefetch ederek anlık geçişler sağlar:

import Link from 'next/link';

export default function Navigation() {
  return (
    <nav>
      <Link href="/">Ana Sayfa</Link>
      <Link href="/about">Hakkında</Link>
      <Link href="/blog">Blog</Link>
      <Link
        href="/dashboard"
        prefetch={false} // Prefetch'i devre dışı bırak
      >
        Dashboard
      </Link>
    </nav>
  );
}

Programatik Navigasyon

Client Component'lerde useRouter hook'u ile programatik navigasyon yapabilirsiniz:

'use client';

import { useRouter } from 'next/navigation';

export default function LoginForm() {
  const router = useRouter();

  const handleLogin = async () => {
    const success = await login();
    if (success) {
      router.push('/dashboard');
      // veya
      router.replace('/dashboard'); // History'de geri gidemez
      router.refresh(); // Sunucu bileşenlerini yenile
    }
  };

  return (
    <button onClick={handleLogin}>
      Giriş Yap
    </button>
  );
}
Uyarı: useRouter hook'unu next/navigation paketinden import edin, next/router'dan değil. next/router Pages Router içindir.

Aktif sayfayı belirlemek için usePathname hook'unu kullanabilirsiniz:

'use client';

import Link from 'next/link';
import { usePathname } from 'next/navigation';

export default function NavLink({ href, children }: {
  href: string;
  children: React.ReactNode;
}) {
  const pathname = usePathname();
  const isActive = pathname === href;

  return (
    <Link
      href={href}
      className={isActive ? 'text-blue-600 font-bold' : 'text-gray-600'}
    >
      {children}
    </Link>
  );
}

Private Klasörler

Alt çizgi (_) ile başlayan klasörler routing sisteminden çıkarılır ve özel bileşenleri organize etmek için kullanılabilir:

src/app/
├── _components/          # Routing'e dahil edilmez
│   ├── Header.tsx
│   └── Footer.tsx
├── _lib/                 # Routing'e dahil edilmez
│   └── utils.ts
└── page.tsx
Bilgi: Private klasörler URL yapısında görünmez ve sayfalar için kullanılamaz. Bu, proje organizasyonu için güçlü bir araçtır.

Catch-All ve Optional Catch-All Segments

Dinamik segmentleri genişleterek birden fazla alt path'i yakalayabilirsiniz:

// [...slug]/page.tsx — Catch-all
// /shop/a → { slug: ['a'] }
// /shop/a/b → { slug: ['a', 'b'] }
// /shop/a/b/c → { slug: ['a', 'b', 'c'] }
// /shop → 404

// [[...slug]]/page.tsx — Optional Catch-all
// /shop → { slug: undefined }
// /shop/a → { slug: ['a'] }
// /shop/a/b → { slug: ['a', 'b'] }

export default function ShopPage({
  params,
}: {
  params: { slug?: string[] };
}) {
  return <div>Slug: {params.slug?.join('/')}</div>;
}

Sonuç

Next.js App Router, dosya sistemi tabanlı yaklaşımıyla routing işlemlerini son derece sezgisel hale getirir. Layout'lar, route groups, özel dosyalar ve dinamik segmentler ile karmaşık uygulama yapılarını kolayca yönetebilirsiniz. Server Components ile varsayılan olarak gelen performans avantajları da cabası. Bir sonraki yazıda Server Components ve Client Components arasındaki farkları detaylı inceleyeceğiz.

Kaynaklar

İlgili Yazılar