Nuxt 3: SSR ve statik üretim, eksiksiz rehber
Nuxt 3 ile SSR ve statik üretimi tüm yönleriyle öğrenin. useFetch'ten route rules'a, Vue.js uygulamalarınızın performansını optimize edin.

Nuxt 3, farklı kullanım senaryolarına uygun çoklu render modları sunarak Vue.js uygulamalarının inşa şeklini dönüştürür. Server-Side Rendering (SSR), statik üretim ve hibrit render arasında framework, performans ve SEO optimizasyonu için dikkat çekici bir esneklik sağlar.
Bu eğitim Vue 3 ve Composition API hakkında temel bilgi gerektirir. Sunucu tarafı render kavramlarına aşinalık faydalı olur ancak zorunlu değildir; temel bilgiler rehber boyunca açıklanır.
Nuxt 3 render modlarını anlamak
Koda dalmadan önce mevcut render modları arasındaki farkları anlamak şarttır. Her mod; performans, SEO ve kullanıcı deneyimi açısından belirli ihtiyaçlara karşılık gelir.
SSR (Server-Side Rendering) her istek için sunucuda HTML üretir. Statik üretim (SSG) build zamanında tüm sayfaları önceden üretir. Hibrit mod, bu yaklaşımları sayfa bazında birleştirmeyi sağlar.
// Farklı render modlarının yapılandırması
export default defineNuxtConfig({
// SSR varsayılan olarak etkin (SEO için önerilir)
ssr: true,
// Statik üretim: tüm sayfaları önceden render eder
// Build için 'npm run generate' kullanın
// target: 'static', // Nuxt 2 söz dizimi
// Hibrit mod: rota bazında yapılandırılabilir
routeRules: {
// Ana sayfa: önceden render edilmiş ve önbelleğe alınmış
'/': { prerender: true },
// Blog: statik üretim
'/blog/**': { prerender: true },
// Dashboard: yalnızca istemci tarafı render
'/dashboard/**': { ssr: false },
// API: pre-render yok
'/api/**': { prerender: false }
}
})Bu yapılandırma hibrit modun gücünü gösterir: uygulamanın her bölümü kendi ihtiyaçlarına en uygun render modunu kullanır.
useFetch ve useAsyncData ile veri çekme
Nuxt 3, izomorfik şekilde veri çekmek için iki ana composable sunar. Bu composable'lar hem sunucu hem istemci tarafında çalışır ve hidrasyonu otomatik yönetir.
useFetch, HTTP çağrılarını basitleştiren useAsyncData etrafındaki bir wrapper'dır. useAsyncData ileri seviye senaryolarda daha fazla kontrol sunar.
<script setup lang="ts">
// pages/blog/[slug].vue
// useFetch ile makale detay sayfası
// Rota parametresini al
const route = useRoute()
// useFetch: otomatik veri çekme
// Veriler sunucu tarafında çekilir ve istemcide hidre edilir
const { data: article, pending, error } = await useFetch(
`/api/articles/${route.params.slug}`,
{
// Önbellek ve tekilleştirme için benzersiz anahtar
key: `article-${route.params.slug}`,
// Gerekirse veriyi dönüştür
transform: (response) => response.data,
// Önbellek seçenekleri
getCachedData: (key) => {
// Verinin önbellekte olup olmadığını kontrol et
const nuxtApp = useNuxtApp()
return nuxtApp.payload.data[key]
}
}
)
// Navigasyonla hata yönetimi
if (error.value) {
throw createError({
statusCode: 404,
message: 'Makale bulunamadı'
})
}
</script>
<template>
<div>
<div v-if="pending" class="loading">
Makale yükleniyor...
</div>
<article v-else-if="article">
<h1>{{ article.title }}</h1>
<div v-html="article.content" />
</article>
</div>
</template>Daha fazla kontrol gerektiren durumlarda useAsyncData herhangi bir asenkron fonksiyon çalıştırmaya izin verir.
<script setup lang="ts">
// pages/products/index.vue
// useAsyncData ve filtrelerle ürün listesi
const route = useRoute()
// useAsyncData: fetch mantığı üzerinde tam kontrol
const { data: products, refresh } = await useAsyncData(
'products-list',
async () => {
// Gerekirse birden fazla kaynaktan çek
const [productsResponse, categoriesResponse] = await Promise.all([
$fetch('/api/products', {
query: {
category: route.query.category,
sort: route.query.sort || 'date'
}
}),
$fetch('/api/categories')
])
// Verileri birleştir ve dönüştür
return {
products: productsResponse.data,
categories: categoriesResponse.data,
total: productsResponse.meta.total
}
},
{
// Query params değiştiğinde yenile
watch: [() => route.query]
}
)
// Manuel yenileme fonksiyonu
const updateFilters = async (newCategory: string) => {
await navigateTo({
query: { ...route.query, category: newCategory }
})
}
</script>Bu composable'lar çift fetch'i önler: sunucuda alınan veriler HTML payload'una serileştirilir ve istemci hidrasyonu sırasında yeniden kullanılır.
Server hooks ile SSR'ı özelleştirmek
Nuxt 3'ün SSR'ı server hooks aracılığıyla özelleştirilebilir. Bu hook'lar, varsayılan davranışı değiştirmek için render döngüsünün farklı aşamalarına müdahale etmeye olanak tanır.
// SSR render'ını özelleştirmek için sunucu eklentisi
export default defineNitroPlugin((nitroApp) => {
// Her sayfanın render'ından önce çalışan hook
nitroApp.hooks.hook('render:html', (html, { event }) => {
// Script veya metadata enjekte et
html.head.push(`
<script>
// Analitik veya global yapılandırma
window.__APP_CONFIG__ = {
environment: '${process.env.NODE_ENV}',
apiUrl: '${process.env.API_URL}'
}
</script>
`)
})
// Render önbelleğinin yönetimi için hook
nitroApp.hooks.hook('render:response', (response, { event }) => {
// Özel önbellek başlıkları ekle
const path = event.path
if (path.startsWith('/blog/')) {
// Blog makaleleri için uzun önbellek
response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400'
} else if (path.startsWith('/api/')) {
// API'ler için önbellek yok
response.headers['Cache-Control'] = 'no-store'
}
})
})render:response hook'u HTTP önbellek stratejilerini uygulamak için idealdir. SSR'ı Cache-Control başlıklarına saygı gösteren bir CDN ile birleştirmek, önceden render edilmiş sayfaları sunmaya devam ederken bunları geçersiz kılma yeteneğini korur.
nuxt generate ile statik üretim
Statik üretim, build zamanında tüm sayfaları önceden inşa eder. Bu yaklaşım blog, dokümantasyon veya pazarlama siteleri gibi sabit içerikli siteler için idealdir.
Dinamik rotalar için Nuxt'un üretilecek tüm URL'leri bilmesi gerekir. prerender:routes hook'u bu rotaları programatik olarak tanımlamayı sağlar.
// Statik üretim için eksiksiz yapılandırma
export default defineNuxtConfig({
// Statik üretimi etkinleştir
nitro: {
prerender: {
// Otomatik link tarayıcısını etkinleştir
crawlLinks: true,
// Her zaman dahil edilecek rotalar
routes: ['/', '/about', '/contact'],
// Belirli rotaları yoksay
ignore: ['/admin', '/api']
}
},
hooks: {
// Dinamik rotaları üretmek için hook
async 'prerender:routes'(ctx) {
// Makaleleri API veya DB'den çek
const articles = await fetch('https://api.example.com/articles')
.then(res => res.json())
// Makale rotalarını ekle
for (const article of articles) {
ctx.routes.add(`/blog/${article.slug}`)
}
// Kategorileri çek
const categories = await fetch('https://api.example.com/categories')
.then(res => res.json())
for (const category of categories) {
ctx.routes.add(`/category/${category.slug}`)
}
}
}
})Çok sayfalı projelerde otomatik tarayıcı yetersiz kalabilir. İşte ayrı bir yapılandırma dosyasıyla daha sağlam bir yaklaşım.
// Dinamik rota listesini üretmek için yardımcı işlev
import { prisma } from './prisma'
export async function getAllStaticRoutes(): Promise<string[]> {
const routes: string[] = []
// Blog makaleleri
const articles = await prisma.article.findMany({
where: { published: true },
select: { slug: true, category: { select: { slug: true } } }
})
for (const article of articles) {
routes.push(`/blog/${article.category.slug}/${article.slug}`)
}
// Ürün sayfaları
const products = await prisma.product.findMany({
where: { active: true },
select: { slug: true }
})
for (const product of products) {
routes.push(`/products/${product.slug}`)
}
// Etiket sayfaları
const tags = await prisma.tag.findMany({
select: { slug: true }
})
for (const tag of tags) {
routes.push(`/tags/${tag.slug}`)
}
return routes
}Vue.js / Nuxt.js mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
routeRules ile hibrit render
Hibrit render Nuxt 3'ün öne çıkan özelliğidir. Her rota için farklı render kuralları tanımlamayı ve SSR ile SSG'nin en iyi yönlerini birleştirmeyi sağlar.
// Gelişmiş hibrit render yapılandırması
export default defineNuxtConfig({
routeRules: {
// Pazarlama sayfaları: önceden render edilmiş ve uzun süre önbelleklenmiş
'/': { prerender: true },
'/pricing': { prerender: true },
'/features/**': { prerender: true },
// Blog: ISR (Incremental Static Regeneration)
// Saatte bir yeniden doğrulama
'/blog/**': {
isr: 3600,
prerender: true
},
// Dokümantasyon: yeniden doğrulamalı CDN önbelleği
'/docs/**': {
swr: 86400, // Stale-while-revalidate
prerender: true
},
// E-ticaret: kısa önbellekli SSR
'/products/**': {
ssr: true,
cache: {
maxAge: 60,
staleMaxAge: 300
}
},
// Sepet ve ödeme: yalnızca istemci tarafı
'/cart': { ssr: false },
'/checkout/**': { ssr: false },
// Dashboard: SPA modu
'/dashboard/**': {
ssr: false,
// Pre-rendering'i devre dışı bırak
prerender: false
},
// API rotaları: varsayılan olarak önbellek yok
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE'
}
}
}
})Bu yapılandırma tipik bir modern uygulama mimarisini gösterir: kamuya açık sayfalar SEO için SSG ile optimize edilirken etkileşimli bölümler istemci tarafı render kullanır.
Veri önbelleğiyle performans optimizasyonu
Sayfa önbelleğinin ötesinde Nuxt 3, çekilen verileri önbelleklemeyi sağlar. Bu strateji API'ler üzerindeki yükü azaltır ve yanıt sürelerini iyileştirir.
// Veri önbellekli API endpoint'i
import { getArticleBySlug } from '~/server/utils/articles'
export default defineCachedEventHandler(
async (event) => {
const slug = getRouterParam(event, 'slug')
if (!slug) {
throw createError({
statusCode: 400,
message: 'Slug eksik'
})
}
const article = await getArticleBySlug(slug)
if (!article) {
throw createError({
statusCode: 404,
message: 'Makale bulunamadı'
})
}
return article
},
{
// Slug tabanlı önbellek anahtarı
getKey: (event) => `article-${getRouterParam(event, 'slug')}`,
// Önbellek süresi: 1 saat
maxAge: 3600,
// Stale-while-revalidate: güncelleme sırasında eski önbelleği sun
staleMaxAge: 7200,
// Etiket tabanlı geçersiz kılma
tags: ['articles']
}
)İçerik değiştiğinde önbelleği geçersiz kılmak için Nuxt bir etiket sistemi sunar.
// Önbellek geçersiz kılmalı makale güncellemesi
import { updateArticle } from '~/server/utils/articles'
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug')
const body = await readBody(event)
// Makaleyi güncelle
const article = await updateArticle(slug, body)
// Bu makale için önbelleği geçersiz kıl
await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`)
// Veya etiket tabanlı geçersiz kılma (tüm makaleler)
// await useStorage('cache').clear('articles')
return article
})Birden fazla örnekli üretimde bellek içi önbellek yetersiz kalır. Örnekler arasında tutarlılığı sağlamak için Nitro yapılandırması üzerinden Redis veya başka bir dağıtık sistemin kurulması önerilir.
SEO ve metadata yönetimi
SSR, metadata'yı sunucu tarafında üreterek SEO optimizasyonuna olanak tanır. Nuxt 3, meta etiketleri dinamik olarak yönetmek için birkaç yaklaşım sunar.
<script setup lang="ts">
// pages/blog/[slug].vue
// SEO için optimize edilmiş blog sayfası
const route = useRoute()
const { data: article } = await useFetch(`/api/articles/${route.params.slug}`)
// Makale tabanlı dinamik SEO yapılandırması
useSeoMeta({
title: article.value?.title,
description: article.value?.excerpt,
ogTitle: article.value?.title,
ogDescription: article.value?.excerpt,
ogImage: article.value?.coverImage,
ogType: 'article',
twitterCard: 'summary_large_image',
twitterTitle: article.value?.title,
twitterDescription: article.value?.excerpt,
twitterImage: article.value?.coverImage
})
// Google için yapılandırılmış veriler
useHead({
script: [
{
type: 'application/ld+json',
innerHTML: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: article.value?.title,
description: article.value?.excerpt,
image: article.value?.coverImage,
datePublished: article.value?.publishedAt,
dateModified: article.value?.updatedAt,
author: {
'@type': 'Organization',
name: 'SharpSkill'
}
})
}
]
})
</script>Statik sayfalar için metadata doğrudan bileşende tanımlanabilir.
<script setup lang="ts">
// pages/about.vue
// SEO'lu statik sayfa
definePageMeta({
title: 'Hakkında'
})
useSeoMeta({
title: 'SharpSkill Hakkında | Teknik mülakat hazırlığı',
description: 'SharpSkill\'i keşfedin: teknik mülakat hazırlık platformu. Misyon: geliştiricilerin teknik mülakatlarda başarılı olmasına yardımcı olmak.',
ogTitle: 'SharpSkill Hakkında',
ogDescription: 'Teknik mülakat hazırlık platformu',
ogImage: '/images/og-about.webp'
})
</script>Dağıtım ve üretim hususları
Dağıtım seçimi kullanılan render moduna bağlıdır. İşte başlıca seçenekler ve yapılandırmaları.
// Farklı dağıtım ortamları için yapılandırma
export default defineNuxtConfig({
nitro: {
// Hedef platforma göre preset
// preset: 'vercel', // Vercel
// preset: 'netlify', // Netlify
// preset: 'cloudflare-pages', // Cloudflare
// preset: 'node-server', // Klasik Node.js
// Üretimde Node.js için yapılandırma
preset: 'node-server',
// Yanıt sıkıştırması
compressPublicAssets: true,
// Önbellek deposu yapılandırması
storage: {
cache: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
},
// Çalışma zamanı ortam değişkenleri
runtimeConfig: {
// Sırlar (istemciye sunulmaz)
apiSecret: process.env.API_SECRET,
// Genel yapılandırma
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
}
}
})Statik dağıtım için npm run generate komutu, herhangi bir statik dosya barındırıcısında dağıtıma hazır bir .output/public klasörü oluşturur.
# Statik üretim
npm run generate
# .output/public içeriği şunlara dağıtılabilir:
# - Vercel (otomatik tespit)
# - Netlify (otomatik yapılandırma)
# - GitHub Pages
# - S3 + CloudFront
# - Herhangi bir CDN veya statik dosya sunucusuPratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Sonuç
Nuxt 3, Vue.js uygulamalarını render etmek için olağanüstü bir esneklik sunar. SSR, SSG ve hibrit render arasındaki seçim her projenin özel ihtiyaçlarına bağlıdır.
Önemli noktalar:
✅ SSR: iyi SEO gerektiren dinamik içerikler için ideal (e-ticaret, haber siteleri)
✅ SSG: sabit içerikler için mükemmel (bloglar, dokümantasyon, pazarlama siteleri)
✅ Hibrit: çeşitli ihtiyaçlara sahip karmaşık uygulamalar için en iyi yaklaşım
✅ useFetch/useAsyncData: otomatik hidrasyon ve önbellek yönetimi
✅ routeRules: her rotanın davranışı için ince ayarlı yapılandırma
✅ Önbellek: üretim performansını optimize etmek için çoklu stratejiler
Hibrit render'ı iyi düşünülmüş bir önbellek stratejisiyle birleştirmek, Single Page Applications'ın etkileşimini koruyarak SEO için optimize edilmiş yüksek performanslı uygulamalar inşa etmeyi sağlar.
Etiketler
Paylaş
İlgili makaleler

Vue.js mülakat soruları: işi kazandıran 25 temel soru
Vue.js mülakatlarına bu 25 temel soruyla hazırlanın. Reaktiviteden composables'a kadar bir sonraki mülakatta öne çıkmak için anahtar kavramlara hâkim olun.

Nuxt 4 (2026): Yeni Dizin Yapisi ve Nuxt 3'ten Gecis Rehberi
Nuxt 4 ile gelen yeni app/ dizin yapisi, Nuxt 3'ten adim adim gecis sureci, singleton veri cekme katmani, shallow reactivity, TypeScript context splitting, Vue Router v5 entegrasyonu, Unhead v2 degisiklikleri ve kapsamli gecis kontrol listesi.

Vue 3 Pinia vs Vuex: Modern Durum Yönetimi ve Mülakat Soruları 2026
Pinia ve Vuex karşılaştırması: API tasarımı, TypeScript, Composition API entegrasyonu, performans, geçiş yolu ve 2026 Vue mülakat soruları.