Node.js uygulamasında hata ayıklamanın temel yolu inspector'dır: süreci node --inspect app.js ile başlattığınızda Node.js varsayılan olarak 127.0.0.1:9229 adresinde bir hata ayıklama istemcisi bekler; Chrome DevTools, Edge, VS Code ya da yerleşik node inspect bu adrese bağlanıp kesme noktası koymanıza, adım adım ilerlemenize ve değişkenleri incelemenize izin verir. Kodun bağlanmadan önce çalışmaya başlamasını istemiyorsanız --inspect-brk ya da --inspect-wait kullanırsınız.
Bu yazıda üç bayrağın farkını, DevTools ve VS Code ile bağlanmayı, komut satırındaki node inspect hata ayıklayıcısını, v26.1.0 ile gelen probe modunu ve node:inspector modülünü anlatıyoruz. Güvenlik tarafını da atlamıyoruz, çünkü açık bırakılmış bir inspector portu uzaktan kod çalıştırmaya kapı açar. Bellek sızıntısı, heap snapshot ve olay döngüsü gecikmesi gibi performans konuları Node.js performans optimizasyonu yazısında ele alınıyor. Örnekler Node.js v26.13.0 ile Windows üzerinde çalıştırıldı; çıktılardaki yerel yollar /home/kullanici/proje ile değiştirildi.
Inspector nasıl çalışır?
![Inspector nasıl çalışır? --inspect[=host:port], --inspect-wait[=host:port], --inspect-brk[=host:port], --inspect-port=[host:]port](/assets/blog/nodejs-debug-inspect-devtools-b1.webp)
--inspect ile başlatılan bir Node.js süreci, V8 inspector'ı etkinleştirir ve Chrome DevTools Protocol konuşan istemcileri bekler. Her sürece benzersiz bir UUID atanır; istemcinin bağlanmak için adresi, portu ve bu UUID'yi bilmesi gerekir. Node.js tam adresi standart hataya yazar:
$ node --inspect=127.0.0.1:0 sepet.js
Debugger listening on ws://127.0.0.1:6590/699829c3-3c5f-4aaf-af6e-512bd21a827b
For help, see: https://nodejs.org/learn/getting-started/debugging
Toplam: 1660Port olarak 0 verdiğimiz için Node.js boş bir rastgele port seçti; UUID de her oturumda değişir. Bu örnekte --inspect kullandığımız için betik beklemeden çalıştı ve bitti, yani bağlanacak zaman kalmadı. Kısa betiklerde bu yüzden aşağıdaki iki bayraktan birine ihtiyaç duyarsınız. Linux ve macOS'ta çalışan bir sürece SIGUSR1 sinyali göndermek de inspector'ı açar; belgelere göre bu sinyal Windows'ta yoktur ve --disable-sigusr1 ile kapatılabilir. Sinyallerin genel davranışı için process yazısına bakabilirsiniz.
| Bayrak | Ne zaman çalışmaya başlar | Uygun olduğu durum |
|---|---|---|
| --inspect[=host:port] | Hemen, istemci beklenmez | Uzun süre çalışan sunucuya sonradan bağlanmak |
| --inspect-wait[=host:port] | Bir istemci bağlanana kadar bekler | Başlangıç kodunu kaçırmamak |
| --inspect-brk[=host:port] | İstemci bağlanınca ilk satırda durur | Kodu en baştan adım adım izlemek |
| --inspect-port=[host:]port | Inspector açılmaz, yalnızca adresi ayarlar | SIGUSR1 ile sonradan açılacak inspector |
| node inspect betik.js | Betiği alt süreçte --inspect ile başlatır | Terminalden hızlı hata ayıklama |
Belgelerdeki ayrım şöyledir: --inspect-wait hata ayıklayıcı bağlanana kadar kodu çalıştırmaz, bağlandığında ise kod normal akışında devam eder; --inspect-brk ise bağlantıdan sonra kullanıcı kodunun ilk satırında durur. --inspect-wait v22.2.0 ile eklendi; diğer ikisi çok daha eskidir. Bu bayrakları node --test ile birleştiremezsiniz; test çalıştırıcısı inspector ile birlikte kullanılamaz. Testlerde hata ayıklamak istiyorsanız tek test dosyasını node --inspect-brk dosya.test.mjs gibi doğrudan çalıştırabilirsiniz. Test yazımı için node:test rehberine bakın.
Chrome DevTools ve Edge ile bağlanmak
Tarayıcıda chrome://inspect (Edge'de edge://inspect) sayfasını açın. Configure düğmesiyle hedef adres ve portun listede olduğundan emin olun; Node.js süreciniz Remote Target listesinde görünür ve inspect bağlantısıyla DevTools açılır. İkinci yol elle bağlanmaktır: http://localhost:9229/json/list adresi bir JSON döndürür, içindeki devtoolsFrontendUrl değerini kopyalayıp tarayıcının adres çubuğuna yapıştırırsınız. Varsayılan olarak WebSocket adresi hem standart hataya hem de bu /json/list uç noktasına yazılır; --inspect-publish-uid=stderr,http bayrağı bunu değiştirir.
DevTools açıldığında Sources panelinde dosyalarınızı görür, satır numarasına tıklayarak kesme noktası koyarsınız. Koşullu kesme noktası, call stack ve scope panelleri tarayıcıda alıştığınız gibi çalışır. Kodun içine debugger; ifadesi yazmak da bir istemci bağlıyken orada durmayı sağlar; istemci bağlı değilse ifade hiçbir şey yapmaz.
VS Code ve diğer istemciler
Learn rehberine göre VS Code'da Debug panelindeki ayar simgesiyle .vscode/launch.json dosyasını açıp Node.js seçmeniz yeterlidir; editör süreci kendisi --inspect ile başlatır ya da çalışan bir sürece bağlanır. JetBrains IDE'leri Node.js hata ayıklama yapılandırmasında --inspect kullanır; Visual Studio ve Eclipse Wild Web Developer da desteklenen istemciler arasında sayılır. Ayrıntılı editör ayarları her aracın kendi belgesindedir; bu yazı Node.js tarafını anlatıyor. TypeScript kaynağıyla hata ayıklarken satır numaralarının tutması için kaynak haritaları devreye girer; --enable-source-maps gibi bayraklar CLI bayrakları yazısında anlatılıyor.
Terminalde node inspect

Yerleşik hata ayıklayıcı tam bir IDE değildir ama adım adım ilerlemek ve değer okumak için yeterlidir. node inspect betik.js, betiği alt süreçte inspector açık olarak başlatır ve ana süreçte komut satırı istemcisini çalıştırır. Aşağıdaki dosyada debugger ifadesi var:
// durak.js
function kdvEkle(tutar, oran) {
const kdv = tutar * oran;
debugger;
return tutar + kdv;
}
console.log(kdvEkle(1000, 0.2));$ node inspect --port=0 durak.js
< Debugger listening on ws://127.0.0.1:45626/e13d21f6-4695-4c16-ae0c-293a87029228
< For help, see: https://nodejs.org/learn/getting-started/debugging
<
connecting to 127.0.0.1:45626 ... ok
< Debugger attached.
<
Break on start in durak.js:6
4 return tutar + kdv;
5 }
> 6 console.log(kdvEkle(1000, 0.2));
7
debug> cont
break in durak.js:3
1 function kdvEkle(tutar, oran) {
2 const kdv = tutar * oran;
> 3 debugger;
4 return tutar + kdv;
5 }
debug> exec kdv
200
debug> bt
#0 kdvEkle durak.js:3:2
#1 (anonymous) durak.js:6:12
...
debug> cont
< 1200
<
< Waiting for the debugger to disconnect...
debug> .exitDökümde debug> isteminden sonraki kelimeler bizim yazdığımız komutlardır. Hata ayıklayıcı varsayılan olarak ilk çalıştırılabilir satırda durur; cont ile debugger ifadesine kadar ilerledik, exec kdv ile değişkenin değerini okuduk, bt ile çağrı yığınını gördük (yığın kısaltıldı). İlk satırda durmadan doğrudan ilk kesme noktasına gitmek için belgeler NODE_INSPECT_RESUME_ON_START=1 ortam değişkenini gösterir. Bizim denememizde varsayılan 9229 portu açılamadığı için --port=0 ile rastgele port seçtik; portunuz başka bir süreç tarafından kullanılıyorsa aynı yolu izleyebilirsiniz. Komut girmeden Enter'a basmak son komutu tekrarlar.
| Komut | Kısa hâli | Ne yapar |
|---|---|---|
| cont | c | Bir sonraki kesme noktasına kadar devam eder |
| next | n | Sonraki satıra geçer |
| step | s | Fonksiyonun içine girer |
| out | o | Fonksiyondan çıkar |
| setBreakpoint(satır) | sb(satır) | Kesme noktası koyar; dosya ve koşul da verilebilir |
| clearBreakpoint(dosya, satır) | cb(...) | Kesme noktasını kaldırır |
| exec ifade | p ifade | İfadeyi o anki bağlamda çalıştırıp yazar |
| watch(ifade) | yok | Her durakta ifadenin değerini gösterir |
| backtrace | bt | Çağrı yığınını yazar |
| repl | yok | Betiğin bağlamında REPL açar |
setBreakpoint('main.js', 4, 'num < 0') biçimi koşullu kesme noktası koyar; yalnızca koşul doğru olduğunda durur. Henüz yüklenmemiş bir modüle de kesme noktası koyabilirsiniz; hata ayıklayıcı bir uyarı verir ve modül yüklendiğinde durur. repl komutu, Node.js REPL'ine benzeyen ama duraklatılmış betiğin değişkenlerine erişen bir oturum açar. profile, profileEnd ve takeHeapSnapshot() komutları da vardır; bunların yorumlanması performans konusudur.
Probe modu: kodu değiştirmeden değer yazdırmak
Çoğu zaman tek istediğiniz, bir satırdaki değişkenin değerini görmektir. Bunun için koda console.log ekleyip sonra silmek yerine, v26.1.0 ile gelen probe modunu kullanabilirsiniz. Belgelerde kararlılığı 1 - Experimental olarak işaretlidir. node inspect --probe dosya:satır --expr ifade biçiminde yazılır; yürütme o satıra her ulaştığında ifade hesaplanır ve oturum bitince tek bir rapor basılır:
// sepet.js
const urunler = [
{ ad: 'Klavye', fiyat: 750, adet: 1 },
{ ad: 'Fare', fiyat: 320, adet: 2 },
{ ad: 'Kablo', fiyat: 90, adet: 3 },
];
let toplam = 0;
for (const u of urunler) {
toplam += u.fiyat * u.adet;
}
console.log('Toplam:', toplam);$ node inspect --probe sepet.js:8 --expr 'u.ad' --probe sepet.js:8 --expr 'toplam' sepet.js
Hit 1 at file:///home/kullanici/proje/sepet.js:8:15
u.ad = "Klavye"
Hit 1 at file:///home/kullanici/proje/sepet.js:8:15
toplam = 0
Hit 2 at file:///home/kullanici/proje/sepet.js:8:15
u.ad = "Fare"
Hit 2 at file:///home/kullanici/proje/sepet.js:8:15
toplam = 750
Hit 3 at file:///home/kullanici/proje/sepet.js:8:15
u.ad = "Kablo"
Hit 3 at file:///home/kullanici/proje/sepet.js:8:15
toplam = 1390
Completed
$ node inspect --probe sepet.js:8 --expr 'toplam' --cond 'u.adet > 1' sepet.js
Hit 1 at file:///home/kullanici/proje/sepet.js:8:15
toplam = 750
Hit 2 at file:///home/kullanici/proje/sepet.js:8:15
toplam = 1390
CompletedDeğerler satır çalışmadan önceki hâli gösterir; bu yüzden ilk turda toplam sıfır. Programın kendi Toplam: 1660 çıktısı görünmedi, çünkü belgelere göre probe modu yalnızca son raporu yazar ve alt sürecin çıktısını susturur. Aynı konumu paylaşan ifadeler aynı duraklamada, komut satırındaki sırayla hesaplanır. v26.6.0 ile eklenen --cond yalnızca koşul doğruyken kayıt alır, v26.4.0 ile gelen --max-hit n kayıt sayısını sınırlar. --json yapılandırılmış çıktı verir, --timeout bütün oturum için süre sınırıdır ve varsayılanı 30000 milisaniyedir.
Mini örnek: yanlış fatura toplamını bulmak
Probe modunun gücü, hatanın nerede başladığını kodu değiştirmeden görebilmenizdir. Aşağıdaki betik JSON'dan okunan üç satırın tutarını topluyor ama sonuç tuhaf çıkıyor:
// fatura.js
const satirlar = JSON.parse('[{"tutar":100},{"tutar":"250"},{"tutar":50}]');
let toplam = 0;
for (const s of satirlar) {
toplam = toplam + s.tutar;
}
console.log('Fatura toplamı:', toplam); // çıktı: Fatura toplamı: 10025050Beklenen 400 yerine 10025050 geldi. Döngünün içindeki 4. satırda hem tutarın tipini hem de o anki toplamı yoklayalım:
$ node inspect --probe fatura.js:4 --expr 'typeof s.tutar' --probe fatura.js:4 --expr 'toplam' fatura.js
Hit 1 at file:///home/kullanici/proje/fatura.js:4:23
typeof s.tutar = "number"
Hit 1 at file:///home/kullanici/proje/fatura.js:4:23
toplam = 0
Hit 2 at file:///home/kullanici/proje/fatura.js:4:23
typeof s.tutar = "string"
Hit 2 at file:///home/kullanici/proje/fatura.js:4:23
toplam = 100
Hit 3 at file:///home/kullanici/proje/fatura.js:4:23
typeof s.tutar = "number"
Hit 3 at file:///home/kullanici/proje/fatura.js:4:23
toplam = "100250"
Completedİkinci turda tutarın metin olduğu, üçüncü turda da toplamın artık bir metne dönüştüğü açıkça görülüyor: sayı ile metni + ile toplamak birleştirme yapar. Çözüm, veriyi okurken Number(s.tutar) ile dönüştürmektir; bu davranışın nedenleri tip dönüşümü yazısında anlatılıyor. Aynı soruyu bir araca vermek istiyorsanız --json ekleyin; --max-hit 1 ile ilk kayıttan sonra oturum biter. Rapor tek satırlık JSON olarak gelir ve her kayıtta location, result.type ve result.value alanları bulunur:
$ node inspect --json --probe fatura.js:4 --expr 'toplam' --max-hit 1 fatura.js
{"v":2,"probes":[{"expr":"toplam","target":{"suffix":"fatura.js","line":4},"maxHit":1}],"results":[{"probe":0,"event":"hit","hit":1,"location":{"url":"file:///home/kullanici/proje/fatura.js","line":4,"column":23},"result":{"type":"number","value":0,"description":"0"}},{"event":"completed"}]}node:inspector modülü
Inspector'ı komut satırı bayrağı yerine koddan da açabilirsiniz. inspector.open(port, host, wait) çağrısı --inspect ile aynı işi süreç başladıktan sonra yapar, inspector.url() etkin adresi ya da yoksa undefined döndürür, inspector.close() sunucuyu kapatır:
// url.mjs
import inspector from 'node:inspector';
console.log('açık mı:', inspector.url() !== undefined); // çıktı: açık mı: false
inspector.open(0);
const adres = new URL(inspector.url());
console.log('protokol:', adres.protocol, 'host:', adres.hostname); // çıktı: protokol: ws: host: 127.0.0.1
inspector.close();
console.log('kapandıktan sonra:', inspector.url()); // çıktı: kapandıktan sonra: undefinedÇalıştırdığınızda open() çağrısı sırasında standart hataya yine "Debugger listening on ..." satırı yazılır. Bu yöntem, örneğin yalnızca bir yönetici komutuyla inspector açmak istediğiniz durumlarda işe yarar. inspector.waitForDebugger() bir istemci bağlanana kadar bekler. Modülün kendisi kararlıdır; node:inspector/promises altındaki Promise API ise 1 - Experimental düzeyindedir. inspector.Session ile Chrome DevTools Protocol mesajları gönderebilirsiniz, ancak belgeler aynı iş parçacığına bağlanan bir oturumla kesme noktası koymamanızı söyler: duraklatılan program hata ayıklayıcının kendisidir.
Güvenlik: inspector portunu asla dışarı açmayın
Hata ayıklayıcı, Node.js çalışma ortamına tam erişime sahiptir; bu porta bağlanabilen herkes süreç adına keyfi kod çalıştırabilir. node --inspect varsayılan olarak 127.0.0.1 adresine bağlanır. --inspect=0.0.0.0 gibi açık bir adres verdiğinizde, port güvenlik duvarıyla korunmuyorsa belgelerin deyimiyle uzaktan kod çalıştırma saldırısına açık olursunuz. Yerel adrese bağlı olsa bile aynı makinedeki her uygulama inspector'a sınırsız erişebilir; bu tasarım gereğidir.
Tarayıcılardaki web siteleri için ek önlem vardır: Node.js, DNS rebinding saldırılarına karşı bağlantının Host başlığının bir IP adresi ya da tam olarak localhost olduğunu doğrular. Uzak bir sunucudaki süreçte hata ayıklamanız gerekiyorsa Learn rehberinin önerisi, inspector'ı sunucuda yerel adreste bırakıp kendi makinenizden SSH tüneli açmaktır:
# Sunucuda (inspector yalnızca localhost'u dinler)
node --inspect server.js
# Kendi makinenizde: yerel 9221 portunu sunucunun 9229 portuna yönlendirir
ssh -L 9221:localhost:9229 kullanici@sunucu.ornek.comBundan sonra DevTools ya da VS Code'u localhost:9221 adresine bağlarsınız. İzin modeliyle çalışan bir süreçte inspector varsayılan olarak kısıtlanır ve SIGUSR1 dinleyicisi oluşturulmaz; --allow-inspector bayrağı bu kısıtı kaldırır ve 1.0 - Early development düzeyindedir. Ayrıntılar izin modeli yazısında. Servisi systemd ile çalıştırıyorsanız üretimde inspector bayraklarını birim dosyasına eklememeye dikkat edin; birim dosyaları için systemd servis dosyası rehberine bakabilirsiniz.
Sık yapılan hatalar

- Kısa betikte --inspect kullanmak: betik bağlanmadan biter.
--inspect-brkveya--inspect-waitkullanın. - Portu 0.0.0.0 adresine açmak: güvenlik duvarı yoksa uzaktan kod çalıştırma riski doğar; SSH tüneli tercih edin.
- Port çakışması: 9229 kullanılamıyorsa
--inspect=127.0.0.1:0ya danode inspect --port=0ile rastgele port seçtirin. - --test ile --inspect birleştirmek: test çalıştırıcısı inspector ile birlikte kullanılamaz; dosyayı doğrudan çalıştırın.
- Probe ile TDZ'ye düşmek: değişkeni tanımlandığı satırda değil, sonraki bir satırda yoklayın.
- debugger ifadesini kodda unutmak: istemci bağlı değilken etkisizdir ama bir gün biri bağlandığında uygulama orada durur; işiniz bitince silin.
- Windows'ta SIGUSR1 beklemek: bu sinyal Windows'ta yoktur;
inspector.open()ile koddan açabilirsiniz.
Sık Sorulan Sorular
--inspect ile --inspect-brk arasındaki fark nedir?
--inspect kodu hemen çalıştırır ve istemciyi beklemez. --inspect-brk istemci bağlandığında kullanıcı kodunun ilk satırında durur. Arada bir seçenek olan --inspect-wait istemciyi bekler ama ilk satırda durmaz.
Çalışan bir üretim sürecine bağlanabilir miyim?
Linux ve macOS'ta SIGUSR1 sinyaliyle inspector açılabilir, ancak bu süreç üzerinde tam yetki vermek demektir. Yalnızca yerel adreste, gerekirse SSH tüneliyle ve kısa süreliğine yapın; bitince süreci yeniden başlatmak en temiz yoldur.
Probe modu üretimde kullanılabilir mi?
Probe modu deneyseldir ve şu an yalnızca komut satırında verilen giriş betiğiyle yeni bir süreç başlatmayı destekler. Çalışan bir sürece bağlanamaz; geliştirme sırasında console.log yerine kullanmak için uygundur.
Testlerde nasıl hata ayıklarım?
node --test inspector ile birleşmediği için tek test dosyasını node --inspect-brk dosya.test.mjs ile çalıştırın. Birden fazla test süreci başlatan run() API'si, alt süreçlerin portunu ayarlamak için inspectPort seçeneğini sunar.
node inspect ile CPU profili veya heap snapshot alabilir miyim?
Evet. Hata ayıklayıcıda profile komutu CPU profilini başlatır, profileEnd durdurur ve profiles[0].save() sonucu varsayılan olarak node.cpuprofile dosyasına yazar. takeHeapSnapshot() ise belleğin anlık görüntüsünü node.heapsnapshot dosyasına kaydeder. Bu dosyaları DevTools ile açıp yorumlamak performans analizinin konusudur; adımları performans optimizasyonu yazısında bulabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Node.js öğrenme rehberi · node:test rehberi · CLI bayrakları · İzin modeli · Node.js performans optimizasyonu · JavaScript hata yönetimi