Deno Deploy ile İlk Uygulamayı Dakikalar İçinde Yayınlama
Klasik bir web uygulaması yayınlamak istediğinizde aklınıza ne geliyor? Sunucu kurmak, Nginx yapılandırmak, SSL sertifikası almak, firewall kuralları yazmak… Bunların hepsi zaman alan ve hata yapma olasılığı yüksek işlemler. Deno Deploy ise bu sürecin tamamını ortadan kaldırıyor. Kodunuzu yazıyorsunuz, deployctl deploy komutunu çalıştırıyorsunuz ve uygulamanız dakikalar içinde dünya genelindeki edge sunucularda çalışmaya başlıyor. Bu yazıda gerçek dünya senaryolarıyla Deno Deploy’u inceleyeceğiz.
Deno Deploy Nedir ve Neden Önemli?
Deno Deploy, Deno’nun resmi sunucusuz (serverless) edge computing platformudur. Uygulamalarınız merkezi bir sunucuda değil, dünya genelinde dağıtılmış 35’ten fazla lokasyonda çalışır. Bu sayede kullanıcılarınız her zaman kendilerine en yakın sunucudan yanıt alır.
Geleneksel yaklaşımdan farkı şu: Bir VPS alıyorsunuz, Frankfurt’ta bir sunucu açıyorsunuz ve Türkiye’deki kullanıcılarınız bu sunucuya ulaşıyor. İstanbul’daki bir kullanıcı için latency kabul edilebilir olsa da Tokyo veya São Paulo’daki kullanıcılar için durum hiç iyi değil. Deno Deploy’da ise kodunuz otomatik olarak tüm bu lokasyonlara dağıtılıyor.
Edge Computing avantajları:
- Kullanıcıya yakın hesaplama gücü
- Otomatik ölçekleme, sıfır yapılandırma
- Soğuk başlangıç süresi milisaniyeler mertebesinde
- Global CDN entegrasyonu ücretsiz
Deno Deploy’un teknik özellikleri:
- V8 Isolate tabanlı çalışma ortamı
- WebAssembly desteği
- Web standart API’leri (Fetch, Streams, Workers)
- TypeScript native desteği, derleme gerekmez
- KV (Key-Value) veritabanı entegrasyonu
Ortam Kurulumu
Önce Deno’nun sisteminizde kurulu olduğundan emin olalım.
# Linux ve macOS için Deno kurulumu
curl -fsSL https://deno.land/x/install/install.sh | sh
# Windows için PowerShell ile
irm https://deno.land/install.ps1 | iex
# Kurulumu doğrulayın
deno --version
Deno kurulduktan sonra deployctl aracını yüklememiz gerekiyor. Bu araç Deno Deploy ile etkileşimimizi sağlayacak.
# deployctl kurulumu
deno install --allow-read --allow-write --allow-env --allow-net --allow-run
--no-check -r -f https://deno.land/x/deploy/deployctl.ts
# Kurulumu kontrol edin
deployctl --version
Şimdi Deno Deploy hesabı oluşturmanız gerekiyor. [dash.deno.com](https://dash.deno.com) adresine gidip GitHub hesabınızla giriş yapabilirsiniz. Ücretsiz plan günde 100.000 istek ve 100 GiB veri transferi içeriyor, küçük ve orta ölçekli projeler için fazlasıyla yeterli.
İlk Uygulamanızı Yazma
Temel bir HTTP sunucusuyla başlayalım. Deno Deploy, standart Web API’lerini kullandığı için fetch event’ini dinleyerek çalışıyor.
// main.ts
Deno.serve((req: Request) => {
const url = new URL(req.url);
if (url.pathname === "/") {
return new Response(
JSON.stringify({
mesaj: "Merhaba Deno Deploy!",
zaman: new Date().toISOString(),
lokasyon: Deno.env.get("DENO_REGION") ?? "bilinmiyor",
}),
{
headers: {
"Content-Type": "application/json",
"X-Powered-By": "Deno Deploy",
},
}
);
}
if (url.pathname === "/saglik") {
return new Response("OK", { status: 200 });
}
return new Response("Sayfa bulunamadı", { status: 404 });
});
Bu kodu yerel ortamda test edelim:
# Yerel geliştirme sunucusu
deno run --allow-net --allow-env main.ts
# Veya watch modunda (dosya değişikliklerini otomatik yakalar)
deno run --allow-net --allow-env --watch main.ts
Tarayıcınızda http://localhost:8000 adresine gittiğinizde JSON yanıtı göreceksiniz. DENO_REGION değişkeni lokalde boş gelecek, Deploy’da ise gerçek bölge bilgisini içerecek.
Deploy Token Oluşturma ve İlk Yayın
Dashboard’dan API token oluşturmak için Ayarlar > Access Tokens bölümüne gidin ve yeni bir token üretin. Bu token’ı güvenli bir yerde saklayın.
# Token'ı ortam değişkeni olarak ayarlayın
export DENO_DEPLOY_TOKEN="ddp_xxxxxxxxxxxxxx"
# İlk deploy işlemi
deployctl deploy --project=benim-projem main.ts
# Eğer proje henüz yoksa otomatik oluşturulsun
deployctl deploy --project=benim-projem --create main.ts
Bu kadar. Birkaç saniye sonra https://benim-projem.deno.dev adresinde uygulamanız canlıya alınmış olacak.
Gerçek Dünya Senaryosu: REST API Geliştirme
Gerçek bir API uygulaması yazalım. Ürün kataloğu yöneten basit bir e-ticaret API’si oluşturacağız.
// api.ts
interface Urun {
id: number;
ad: string;
fiyat: number;
stok: number;
kategori: string;
}
const urunler: Urun[] = [
{ id: 1, ad: "Mekanik Klavye", fiyat: 1250, stok: 45, kategori: "elektronik" },
{ id: 2, ad: "USB-C Hub", fiyat: 340, stok: 120, kategori: "elektronik" },
{ id: 3, ad: "Ergonomik Sandalye", fiyat: 4500, stok: 12, kategori: "mobilya" },
];
function jsonYanit(data: unknown, durum = 200): Response {
return new Response(JSON.stringify(data, null, 2), {
status: durum,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
}
Deno.serve(async (req: Request) => {
const url = new URL(req.url);
const yol = url.pathname;
const metod = req.method;
// GET /urunler - Tüm ürünleri listele
if (yol === "/urunler" && metod === "GET") {
const kategori = url.searchParams.get("kategori");
const filtrelenmis = kategori
? urunler.filter((u) => u.kategori === kategori)
: urunler;
return jsonYanit({ toplam: filtrelenmis.length, veri: filtrelenmis });
}
// GET /urunler/:id - Tek ürün getir
const tekUrunEslesme = yol.match(/^/urunler/(d+)$/);
if (tekUrunEslesme && metod === "GET") {
const id = parseInt(tekUrunEslesme[1]);
const urun = urunler.find((u) => u.id === id);
if (!urun) return jsonYanit({ hata: "Ürün bulunamadı" }, 404);
return jsonYanit(urun);
}
// POST /urunler - Yeni ürün ekle
if (yol === "/urunler" && metod === "POST") {
const govde = await req.json();
const yeniUrun: Urun = {
id: urunler.length + 1,
ad: govde.ad,
fiyat: govde.fiyat,
stok: govde.stok ?? 0,
kategori: govde.kategori,
};
urunler.push(yeniUrun);
return jsonYanit(yeniUrun, 201);
}
return jsonYanit({ hata: "Bulunamadı" }, 404);
});
Bu API’yi test edelim:
# Tüm ürünleri listele
curl https://benim-api.deno.dev/urunler
# Kategoriye göre filtrele
curl "https://benim-api.deno.dev/urunler?kategori=elektronik"
# Belirli bir ürünü getir
curl https://benim-api.deno.dev/urunler/1
# Yeni ürün ekle
curl -X POST https://benim-api.deno.dev/urunler
-H "Content-Type: application/json"
-d '{"ad":"Mouse Pad","fiyat":150,"stok":200,"kategori":"aksesuar"}'
Deno KV ile Kalıcı Veri Saklama
Yukarıdaki örnek bellekte veri tutuyor, yani deploy sonrası sıfırlanıyor. Deno Deploy’un yerleşik KV veritabanını kullanalım.
// kv-api.ts
const kv = await Deno.openKv();
interface Gorev {
id: string;
baslik: string;
tamamlandi: boolean;
olusturulma: string;
}
Deno.serve(async (req: Request) => {
const url = new URL(req.url);
const yol = url.pathname;
// Tüm görevleri listele
if (yol === "/gorevler" && req.method === "GET") {
const gorevler: Gorev[] = [];
const liste = kv.list<Gorev>({ prefix: ["gorevler"] });
for await (const eleman of liste) {
gorevler.push(eleman.value);
}
return new Response(JSON.stringify(gorevler), {
headers: { "Content-Type": "application/json" },
});
}
// Yeni görev oluştur
if (yol === "/gorevler" && req.method === "POST") {
const govde = await req.json();
const id = crypto.randomUUID();
const gorev: Gorev = {
id,
baslik: govde.baslik,
tamamlandi: false,
olusturulma: new Date().toISOString(),
};
await kv.set(["gorevler", id], gorev);
return new Response(JSON.stringify(gorev), {
status: 201,
headers: { "Content-Type": "application/json" },
});
}
// Görevi tamamlandı olarak işaretle
if (yol.startsWith("/gorevler/") && req.method === "PATCH") {
const id = yol.split("/")[2];
const mevcut = await kv.get<Gorev>(["gorevler", id]);
if (!mevcut.value) {
return new Response(JSON.stringify({ hata: "Görev bulunamadı" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
const guncellenmis = { ...mevcut.value, tamamlandi: true };
await kv.set(["gorevler", id], guncellenmis);
return new Response(JSON.stringify(guncellenmis), {
headers: { "Content-Type": "application/json" },
});
}
return new Response("Bulunamadı", { status: 404 });
});
KV veritabanı global olarak replike ediliyor. İstanbul’daki bir kullanıcı görev oluşturduğunda Tokyo’daki kullanıcı da birkaç milisaniye içinde bu görevi görebiliyor.
GitHub Actions ile CI/CD Entegrasyonu
Production ortamında otomatik deploy pipeline kurmak kritik önem taşıyor. Her main branch’e push yapıldığında otomatik olarak deploy edilmesini sağlayalım.
# .github/workflows/deploy.yml
name: Deno Deploy
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Kodu indir
uses: actions/checkout@v4
- name: Deno kur
uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- name: Testleri çalıştır
run: deno test --allow-net --allow-env
- name: Deno Deploy'a yayınla
uses: denoland/deployctl@v1
with:
project: "benim-projem"
entrypoint: "main.ts"
root: "."
env:
DENO_DEPLOY_TOKEN: ${{ secrets.DENO_DEPLOY_TOKEN }}
GitHub repository ayarlarından DENO_DEPLOY_TOKEN secret’ını eklemeyi unutmayın. Bu pipeline şunları yapıyor: önce testleri çalıştırıyor, testler geçerse deploy ediyor. Pull request’lerde ise preview URL oluşturuyor, böylece değişiklikleri production’a almadan önce test edebiliyorsunuz.
Ortam Değişkenleri ve Gizli Anahtarlar
Veritabanı bağlantı bilgileri veya API anahtarları gibi hassas verileri kod içinde tutmak güvenlik açığıdır. Deno Deploy’da bu bilgileri nasıl yönetiyoruz?
# Dashboard üzerinden değişken eklemek yerine deployctl ile de yapabilirsiniz
# Önce .env dosyası oluşturun (git'e eklemeyin!)
# .env
DB_BAGLANTI_DIZISI=postgresql://kullanici:sifre@host:5432/veritabani
STRIPE_GIZLI_ANAHTAR=sk_live_xxxxxxxxxxxx
JWT_GIZLI=super_gizli_anahtar_buraya
Kodunuzda bu değişkenlere erişim:
// config.ts
const dbBaglantiDizisi = Deno.env.get("DB_BAGLANTI_DIZISI");
const stripeAnahtar = Deno.env.get("STRIPE_GIZLI_ANAHTAR");
const jwtGizli = Deno.env.get("JWT_GIZLI");
if (!dbBaglantiDizisi || !stripeAnahtar || !jwtGizli) {
throw new Error("Gerekli ortam değişkenleri eksik! Lütfen deploy ayarlarını kontrol edin.");
}
export const config = {
db: dbBaglantiDizisi,
stripe: stripeAnahtar,
jwt: jwtGizli,
ortam: Deno.env.get("DENO_DEPLOYMENT_ID") ? "production" : "gelistirme",
bolge: Deno.env.get("DENO_REGION") ?? "yerel",
};
Dashboard üzerinden değişken eklemek için Settings > Environment Variables bölümüne gidin. Bu değişkenler şifreli olarak saklanıyor ve deploy sırasında otomatik olarak enjekte ediliyor.
Özel Domain Bağlama
uygulamaniz.deno.dev adresi geliştirme için yeterli olsa da production’da kendi domaininizi kullanmak isteyeceksiniz.
Domainini bağlamak için adımlar:
Dashboard üzerinden:
- Projenize gidin
- Settings > Domains bölümüne tıklayın
- “Add Domain” butonuna basın
- Domain adınızı girin (örneğin
api.sirketiniz.com)
DNS ayarları:
- CNAME kaydı:
api->benim-projem.deno.dev - Veya A kaydı Deno Deploy’un IP adreslerine yönlendirme
# DNS yayılımını kontrol edin
dig api.sirketiniz.com CNAME
# SSL sertifikasının aktif olup olmadığını kontrol edin
curl -I https://api.sirketiniz.com
Deno Deploy, SSL sertifikasını Let’s Encrypt üzerinden otomatik olarak alıp yönetiyor. Sertifika yenileme işlemleriyle hiç uğraşmıyorsunuz.
Performans İzleme ve Hata Ayıklama
Dashboard’daki Logs sekmesi gerçek zamanlı log akışı sunuyor. Ancak production uygulamalarında yapılandırılmış loglama kritik önem taşıyor.
// logger.ts
type LogSeviyesi = "bilgi" | "uyari" | "hata" | "kritik";
interface LogGirdisi {
seviye: LogSeviyesi;
mesaj: string;
zaman: string;
bolge: string;
[anahtar: string]: unknown;
}
function log(seviye: LogSeviyesi, mesaj: string, ekstra?: Record<string, unknown>): void {
const girdi: LogGirdisi = {
seviye,
mesaj,
zaman: new Date().toISOString(),
bolge: Deno.env.get("DENO_REGION") ?? "yerel",
...ekstra,
};
// Deno Deploy'da console.log JSON olarak loglanıyor
console.log(JSON.stringify(girdi));
}
// Kullanım örneği
Deno.serve(async (req: Request) => {
const baslangic = Date.now();
const url = new URL(req.url);
log("bilgi", "İstek alındı", {
metod: req.method,
yol: url.pathname,
kullanici_ajanı: req.headers.get("user-agent"),
});
try {
const yanit = await istekIsle(req);
const sure = Date.now() - baslangic;
log("bilgi", "İstek tamamlandı", {
durum: yanit.status,
sure_ms: sure,
});
return yanit;
} catch (hata) {
log("hata", "İstek işlenirken hata", {
hata_mesaji: hata instanceof Error ? hata.message : String(hata),
});
return new Response(JSON.stringify({ hata: "Sunucu hatası" }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
});
async function istekIsle(req: Request): Promise<Response> {
return new Response("Merhaba!", { status: 200 });
}
Dikkat Edilmesi Gereken Kısıtlamalar
Deno Deploy güçlü bir platform olsa da bazı sınırlamalar var:
Dosya sistemi erişimi:
- Deno Deploy’da dosya sistemi erişimi yok.
Deno.readFile,Deno.writeFilegibi API’ler çalışmıyor. - Statik dosyaları serve etmek için onları kod içine gömmeli veya harici bir CDN kullanmalısınız.
Uzun çalışan işlemler:
- İstekler maksimum 30 saniye içinde tamamlanmalı.
- Arka plan işlemleri için Deno Queues kullanabilirsiniz.
- WebSocket bağlantıları destekleniyor ama uzun süreli tutma bazı durumlarda sorun çıkarabilir.
Node.js uyumluluğu:
node:prefix’li modüller kısmen destekleniyor.- npm paketleri büyük çoğunlukla çalışıyor ama bazı native modüller çalışmıyor.
fs,pathgibi Node.js core modülleri kısıtlı çalışıyor.
Bellek ve CPU:
- Her isolate 512 MB bellek limitine sahip.
- CPU yoğun işlemler için dikkatli olun, edge ortamları bu tür yükler için optimize edilmemiş.
Ücretsiz Plan Sınırları
Ücretsiz planda dikkat etmeniz gerekenler:
- Günlük istek limiti: 100.000 istek
- Veri transferi: Ayda 100 GiB
- KV okuma: Günde 450.000 birim
- KV yazma: Günde 300.000 birim
- Özel domain: 1 adet
Limitlere yaklaştığınızda dashboard’dan uyarı alıyorsunuz. Pro plan aylık 20 dolar ve limitleri önemli ölçüde artırıyor.
Sonuç
Deno Deploy, sysadmin ve backend geliştirici olarak beni en çok etkileyen şey altyapı karmaşıklığını neredeyse sıfıra indirmesi oldu. Nginx kurmak, SSL sertifikası yönetmek, load balancer yapılandırmak, global CDN kurmak… Bunların hepsi için ayrı ayrı zaman harcamak yerine doğrudan uygulama geliştirmeye odaklanabiliyorsunuz.
Özellikle şu senaryolar için Deno Deploy mükemmel bir tercih:
- API gateway ve middleware: İstekleri farklı servislere yönlendirme, rate limiting, authentication katmanı ekleme
- Webhook işleyicileri: GitHub, Stripe, Slack webhook’larını edge’de işleme
- A/B test ve feature flag servisleri: Kullanıcı segmentlerine göre farklı içerik sunma
- Dinamik OG görsel üretimi: Social media paylaşımları için gerçek zamanlı görsel üretme
- Basit CRUD API’leri: KV veritabanı ile tam işlevsel API’ler
Tabii her şey Deno Deploy için uygun değil. Dosya sistemi gerektiren, uzun çalışan, yoğun CPU kullanan veya özel sistem kütüphanelerine ihtiyaç duyan uygulamalar için geleneksel VPS ya da container tabanlı çözümler hala en iyi seçenek.
Başlangıç için önerim: mevcut bir projenizin API katmanını veya bir webhook işleyicinizi Deno Deploy’a taşıyın. Platform davranışını küçük bir projede öğrenin, sonra daha büyük şeylere geçin. Ücretsiz plan bu denemeler için gayet yeterli.
