Vercel’de Next.js yayınlamak için ilk iş bütün klasörleri sunucuya taşımak değil, platforma doğru uygulama kökünü ve build sözleşmesini vermek. NextPortfolio arşivimde Next.js, Prisma ve Vercel yapılandırması birlikte bulunuyor. Bu yazıda o dosyalardaki kararları inceliyor, daha küçük bir dağıtım örneği üzerinden önizleme ve üretim akışını anlatıyorum.
Bu rehber gerçek bir Vercel projesi oluşturulduğu veya eski uygulamanın sorunsuz yayımlandığı iddiası değil. Örnek JSON ve health handler’ı yerelde kontrol ediliyor. Güncel PortfolioBlog Angular/.NET süreç modeli ise Render yazısının konusu; sadece vercel.json eklemek o .NET API’yi Next.js fonksiyonuna dönüştürmez.
Önce uygulama kökünü ve framework’ü seçmek
Vercel’de Git deposu içe aktarılır, Framework Preset Next.js olarak doğrulanır ve Root Directory gerçek Next.js package.json dosyasının bulunduğu klasöre ayarlanır. Bir monorepo içindeki örnek klasörünü veya bu Angular projesinin kökünü yanlışlıkla Next.js uygulaması diye seçmem. Lockfile ve Next yapılandırması da seçilen kökle uyumlu olmalı.
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "nextjs",
"installCommand": "npm ci",
"buildCommand": "npm run build"
}
Bu örnek Next.js projesinin köküne aittir. Output Directory’yi genel bir dist klasörüne zorlamıyorum; framework kendi dağıtım çıktısını belirler. NextPortfolio arşivindeki vercel.json içinde ayrıca builds ve PRISMA_GENERATE_DATAPROXY bulunuyor. Bunları yeni rehberde gereksinim kanıtlanmadan taşımıyorum. Normal PostgreSQL bağlantısı için eski Data Proxy bayrağı eklemek, kendi başına bağlantı çözümü değildir.
Prisma client’ı build sırasında üretmek
{
"scripts": {
"dev": "next dev",
"build": "prisma generate && next build",
"start": "next start",
"typecheck": "tsc --noEmit"
}
}
Bu JSON parçası mevcut package.json dosyasının scripts alanına birleştirilir; bağımsız bir uygulama manifesti değildir. Build başında prisma generate çalışınca şema değişikliğinden sonra eski client’ın cache’te kalmasına bel bağlamıyorum. prisma ve @prisma/client paketleri uyumlu sürümde kurulmuş olmalı. Build ortamında gerekli dev araçlarını dışarıda bırakan kurulum yapılırsa komut bulunamaz.
prisma generate tablo oluşturmaz veya canlı migration uygulamaz. Preview açıldı diye üretim veritabanına migrate dev, db push ya da seed çalıştırmıyorum. Şema geçişi kontrollü ve ayrı bir dağıtım adımı; kodu önceki sürüme döndürmek de şemayı otomatik geri almaz. Eski arşivde TypeScript/lint hatalarını atlayan bayraklar bulunuyor; yeşil build’i kalite kanıtı saymadan ayrı typecheck ve ilgili testleri çalıştırmak gerekir.
Prisma 6 ve Prisma 7 ayarını ayırmak
// Prisma 6-style fragment; actual models are defined separately.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
Bu parça NextPortfolio’nun Prisma 6 tarzındaki generator/datasource sözleşmesini gösteriyor; gerçek modeller ayrıca bulunur. Arşivdeki client 6.15 serisinde. Ayrı Prisma rehberim ise 7.10.1, prisma.config.ts ve pg adapter kullanıyor. İki sürümün kurulumunu bir dosyada birleştirmiyorum.
Rust engine kullanan client’ta üretilen engine’in Vercel’in gerçek Node/işletim sistemi/OpenSSL ortamıyla uyuşması gerekir. Arşivde bulunan eski binaryTargets değerini yalnız yerelde çalıştı diye korumam. Paket sürümü ve hedef ortam doğrulanır. Driver adapter’a geçiş de yalnız bir generator satırı değiştirmek değildir; uyumlu Prisma sürümü, adapter ve havuz ayarları birlikte incelenir.
Production, Preview ve Development için ayrı ayarlar
# Prisma 6 runtime. URI-encode the password and CA path.
DATABASE_URL="postgresql://postgres.YOUR_REF:YOUR_PASSWORD@YOUR_POOLER:6543/postgres?pgbouncer=true&connection_limit=1&sslmode=require&sslaccept=strict&sslcert=YOUR_ENCODED_CA_PATH"
# CLI: direct or Session pooler, with separately verified TLS.
DIRECT_URL="postgresql://postgres.YOUR_REF:YOUR_PASSWORD@YOUR_POOLER:5432/postgres?sslmode=require&sslaccept=strict&sslcert=YOUR_ENCODED_CA_PATH"
# Example auth integration name; configure the actual library separately.
AUTH_SECRET=YOUR_RANDOM_SERVER_SECRET
# Safe public URL only; not a secret key.
NEXT_PUBLIC_SITE_URL=https://portfolio.example.com
Örnekteki değerler yer tutucu. Vercel Environment Variables bölümünde her adın hangi ortamda geçerli olduğu seçilir. Preview, canlı veritabanını yanlışlıkla değiştirebilen ikinci bir admin sitesi olmamalı; ayrı geliştirme verisi, sınırlı kimlik bilgisi ve gerekiyorsa ayrı Supabase projesi/şeması kullanılır. Ayrı deployment URL’si tek başına ayrı veritabanı oluşturmaz.
AUTH_SECRET burada Next.js uygulamasının kimlik sağlayıcısı için örnek addır; PortfolioBlog’un Admin__PasswordHash ayarıyla aynı sistem değil. Auth kütüphanesine göre gerekli adlar ve callback URL’leri ayrıca belirlenir. SQL parolası, auth sırrı veya Storage secret anahtarına NEXT_PUBLIC_ öneki eklemem. Bu önek Next.js’in değeri tarayıcıya dahil edebilmesine neden olur.
Ortam değerini panelde değiştirmek mevcut deployment’ı sihirli biçimde yenilemez; ilgili ayarla yeniden deploy gerekir. Build sırasında okunan public değerler de çıktıya gömülebilir. Yerelde .env.local dosyasını doldurmak Vercel projesinin ortamlarını otomatik doldurmaz; CLI ile alınan dosyalar da Git dışında tutulur.
Supabase bağlantısını fonksiyon ömrüne göre kurmak
Prisma 6 örneğinde runtime DATABASE_URL için Supabase Transaction pooler/6543 ve pgbouncer=true gösteriliyor; connection_limit=1 başlangıç bütçesidir, her trafik için performans reçetesi değil. CLI/şema işlemleri için DIRECT_URL doğrudan bağlantıya veya uygun Session/5432 ucuna ayrılır. Sertifika seçenekleri sağlayıcının CA’sıyla doğrulanır; şifre ve dosya yolu URI içinde gerektiği gibi encode edilir.
Bir fonksiyon örneğinde paylaşılan client, bütün deployment’ta tek bağlantı olduğu anlamına gelmez. Paralel örnekler ve Preview’lar havuzu çoğaltır. Her istekte yeni client oluşturmak veya sonunda $disconnect çağırmak yerine uygun modül/süreç ömründe paylaşım ve toplam bağlantı bütçesi düşünülür. Prisma 7 pg adapter’ında eski URL havuz parametrelerinin aynı davranışı vereceği varsayılmaz.
// Merge into the existing Next.js configuration; keep its other options.
export default {
outputFileTracingIncludes: {
'/*': ['./config/supabase-ca.crt'],
},
};
CA dosyası yerelde var diye fonksiyon bundle’ında da bulunmaz. Bu ayar config/supabase-ca.crt public sertifikasını sunucu çıktısına dahil etmek için mevcut Next yapılandırmasına birleştirilir; dosya da projede bulunmalıdır. CLI ve runtime’ın sertifika yolunu kendi çalışma dizinlerinde kontrol etmek gerekir. Sertifika özel anahtar değildir; gerçek sunucu secret anahtarı ise bu dosyaya eklenmez.
import 'server-only';
import { PrismaClient } from '@prisma/client';
const cache = globalThis as typeof globalThis & { prisma?: PrismaClient };
export const prisma = cache.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') cache.prisma = prisma;
Bu eski Prisma client biçimi server-only bir modülde durur. React Client Component bunu içe aktarmaz. Public sorgu Published/Deleted filtrelerini sunucuda uygular; yetkili SQL rolü kullanılıyor diye ziyaretçi otomatik Supabase kullanıcı yetkisine sahip olmaz. Admin erişimi route/server katmanında doğrulanır. ORM’nin tip üretmesi, bir HTTP isteğinin yetkili olduğunu kanıtlamaz.
Basit bir Node route handler ile çalışma kontrolü
// Place at src/app/api/health/route.ts in a Next.js App Router application.
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export function GET(): Response {
return Response.json(
{ status: 'ok' },
{ headers: { 'Cache-Control': 'no-store' } },
);
}
Dosya src/app/api/health/route.ts konumuna yerleşir. runtime=nodejs ve force-dynamic bu örneğin niyetini açık eder; dönen sağlık cevabı cache’lenmez. Bu handler SQL bağlantısını kontrol etmez. Bir public yazı sorgusunu da okumadan veritabanı entegrasyonunun sağlıklı olduğu sonucu çıkarılmaz.
Dosya boyutu ve yerel disk varsayımı
Vercel Functions belgelerindeki istek/cevap payload sınırı 4.5 MB. Mevcut PortfolioBlog API’si 5 MiB görsel ve 6 MiB multipart istek zarfı kabul ediyor. Aynı upload çağrısını bir Vercel Function içinden geçirmek bu sınırda takılabilir; ASP.NET limitini artırmak platform sınırını değiştirmez. Dosya akışı ayrı bir tasarım kararıdır.
Seçenekler arasında mevcut Render API’ye güvenli yükleme akışını korumak veya sunucunun yetkilendirdiği sınırlı bir yükleme yetkisiyle doğrudan Storage’a gitmek bulunur. İkinci tasarım secret anahtarını tarayıcıya vermek değildir. Yerel fonksiyon dosya sistemine yazılan resim de kalıcı medya deposu sayılmaz. Kimlik, dosya boyutu/türü, hedef nesne adı ve yeniden deneme birlikte düşünülür.
Önizlemeden üretime kontrollü ilerlemek
# In the intended Next.js project; these commands need Vercel access.
vercel link
vercel env pull .env.local --environment=development
npm ci
npm run typecheck
npm run build
# Preview deployment, then review before production:
vercel
vercel --prod
Bu komutlar bir yayınlama tarifi; yazı hazırlanırken çalıştırılıp gerçek deployment oluşturulmadı. Link ve env işlemleri doğru Vercel projesinde yapılır. Preview’da ana sayfa, doğrudan blog URL’si, TR/EN metin, admin koruması, bir okuma isteği ve hata akışı incelenir. Canlı domain atamadan önce üretim ayarlarıyla davranış ayrıca değerlendirilir.
Özel domain için Vercel panelinin verdiği DNS kayıtları uygulanır; rastgele bir IP kopyalanmaz. Üretim canonical adresi sabit ve güvenilir bir origin’den üretilir. Preview URL’sinin yanlışlıkla kalıcı canonical olması ya da preview’ın canlı içerikmiş gibi indekslenmesi önlenir. DNS, TLS ve uygulamanın ürettiği metadata aynı değişikliğin farklı kontrolleridir.
Build başarılı, sayfa hatalıysa
- Client eskiyse generate komutunun gerçekten çalıştığı ve aynı şemayı okuduğu kontrol edilir.
- Yalnız Preview’da hata varsa o ortama atanmış değişkenler ve callback URL’si incelenir; Production değerlerinin otomatik paylaşıldığı varsayılmaz.
- Engine veya bağlantı hatasında paket sürümü, gerçek runtime, pooler ve TLS ayarı birlikte kontrol edilir; sertifika denetimi kapatılmaz.
- 413 hatasında uygulama ve platform payload sınırı ayrılır. 401/403 ise yetkilendirme problemi olarak ele alınır.
- Rollback sonrasında eski kodun yeni şemayla uyumu denetlenir; veritabanı kendiliğinden eski hâline dönmez.
Vercel akışı Next.js’in platform tarafından tanınan build ve istek modeline dayanıyor. Render’da kendi süreçlerimi başlatırken aldığım kararların hepsini aynı biçimde buraya taşımıyorum. İki rehberin ortak tarafı, “deploy oldu” sonucunu doğru veri, doğru yetki ve doğru ortamla doğrulamak.