Node.js'te ortam değişkenlerine process.env nesnesi üzerinden erişirsiniz; içe aktarma gerekmez. Bir .env dosyasındaki değerleri ek paket kullanmadan yüklemek için node --env-file=.env app.js komutunu, dosya olmayabilecekse --env-file-if-exists bayrağını, kod içinden yüklemek için process.loadEnvFile() fonksiyonunu, dosya içeriğini yalnızca ayrıştırmak için de util.parseEnv() fonksiyonunu kullanabilirsiniz. Belgeye göre bu araçların tamamı v24.10.0 ve v22.21.0 ile deneysel olmaktan çıktı.

Bu yazı yalnızca Node.js'in yerleşik araçlarını ele alıyor: process.env'in davranışı, Node.js'in .env biçimi için tanımladığı kurallar, birden çok dosya ve öncelik sırası, programatik yükleme ve sık yapılan hatalar. .env dosyalarının genel mantığı, dotenv paketi ve dosyaların güvenli saklanması gibi konuları .env dosyası nedir yazısında anlattık.

process.env nasıl çalışır?

process.env, süreç başlatıldığı anda tanımlı olan kullanıcı ortamını içeren bir nesnedir. Learn rehberindeki örnekte değişkenler komutun önüne yazılarak verilir: USER_ID=239482 USER_KEY=foobar node app.js. Rehber bu yöntemin test için uygun olduğunu, üretimde ise değişkenleri genellikle betiklerle dışa aktaracağınızı belirtir.

Bu nesneyi değiştirebilirsiniz, ancak belgeye göre değişiklikler Node.js sürecinin dışına yansımaz. node -e 'process.env.foo = "bar"' && echo $foo komutu bu yüzden boş satır yazar; değişiklik yalnızca süreç içinde görünür. Atanan her değer metne çevrilir ve bu örtük dönüşüm kullanımdan kaldırılmış (deprecated) bir davranıştır; gelecekteki sürümler metin, sayı veya boolean olmayan değerlerde hata fırlatabilir. Bir değişkeni kaldırmak için delete kullanılır:

javascript
import { env } from 'node:process';
env.Deneme = 1;
console.log(env.DENEME, typeof env.Deneme);
env.BOS = undefined;
console.log(env.BOS, typeof env.BOS);
delete env.BOS;
console.log(env.BOS);
// çıktı: 1 string
// çıktı: undefined string
// çıktı: undefined

Bu çıktıyı Windows'ta aldık ve iki ilginç ayrıntı gösteriyor. Birincisi, env.Deneme ile atanan değeri env.DENEME ile okuyabildik; belgeye göre Windows'ta ortam değişkeni adları büyük küçük harfe duyarsızdır. Linux'ta bu iki ad farklı değişkenlerdir ve ilk satır undefined yazar. İkincisi, undefined atadığımızda değer 'undefined' metnine dönüştü; ikinci satırda gördüğünüz undefined aslında dokuz harflik bir metin. Bir değeri silmek istiyorsanız atama değil delete kullanın.

Worker thread'ler kendi process.env kopyalarını alır: belgeye göre her Worker, aksi belirtilmedikçe ebeveyn thread'in ortamının bir kopyasıyla başlar ve değişiklikler thread'ler arasında görünmez. İşletim sistemine ve yerel eklentilere görünür değişiklik yalnızca ana thread'den yapılabilir. Worker ayrıntıları worker_threads yazısında.

--env-file ile .env dosyası yüklemek

--env-file ile .env dosyası yüklemek: Değişken adı, Geçersiz ad örnekleri, Değer türü, Tırnaklar

--env-file=dosya, geçerli klasöre göre verilen dosyadaki değişkenleri yükler ve process.env üzerinden kullanılabilir hâle getirir. Bayrak v20.6.0 ile eklendi; v21.7.0 ve v20.12.0 ile çok satırlı değer desteği geldi. Dosya yoksa hata fırlatılır. Örnek bir dosya ve onu okuyan betik:

bash
# Uygulama ayarları
PORT=3000
DEBUG=false
APP_NAME="Keydal Demo" # tırnak içindeki değer
export DB_HOST=localhost
SIFRE='a#b=c'
COKLU="birinci satır
ikinci satır"
javascript
import { env } from 'node:process';

console.log(env.PORT, typeof env.PORT);
console.log(env.DEBUG === 'false', Boolean(env.DEBUG));
console.log(env.APP_NAME);
console.log(env.DB_HOST);
console.log(env.SIFRE);
console.log(JSON.stringify(env.COKLU));
bash
node --env-file=.env oku.mjs
# çıktı: 3000 string
# çıktı: true true
# çıktı: Keydal Demo
# çıktı: localhost
# çıktı: a#b=c
# çıktı: "birinci satır\nikinci satır"

Çıktı, belgedeki biçim kurallarının hepsini bir arada gösteriyor. Değerler her zaman metindir: PORT sayı değil '3000', DEBUG ise boolean değil 'false' metni. Bu yüzden Boolean(env.DEBUG) true döndü; boş olmayan her metin truthy'dir. # ile başlayan kısım yorumdur, ama tırnak içindeki # sıradan bir karakter sayılır. Tırnaklar değerden çıkarılır, export öneki yok sayılır ve tırnaklı değerler birden çok satıra yayılabilir.

Node.js'in .env biçimi kuralları

Environment Variables belgesi, .env dosyaları için resmî bir şartname bulunmadığını ve Node.js'in bu yüzden kendi kurallarını tanımladığını söyler. Kurallar şöyle özetlenebilir:

KuralAyrıntı
Değişken adıHarf, rakam ve alt çizgi; rakamla başlayamaz (^[a-zA-Z_]+[a-zA-Z0-9_]*$)
Geçersiz ad örnekleri1_VAR, 'my-var', "my var", VAR_#1
Değer türüHer değer metin olarak okunur; 0, true ve JSON metin kalır
TırnaklarTek, çift tırnak veya ters tırnak; değerden çıkarılır
Çok satırYalnızca tırnaklı değerler birden çok satıra yayılabilir
BoşlukAd ve değer çevresindeki boşluklar, tırnak içinde değilse kırpılır
Yorum# satırın geri kalanını yorum yapar; tırnak içinde yorum sayılmaz
export önekiYok sayılır; dosya kabukta da source edilebilir
Dosya adı.env veya .env.dev gibi önerilir ama zorunlu değildir

Birden çok dosya ve öncelik sırası

Birden çok dosya ve öncelik sırası

--env-file bayrağını birden çok kez verebilirsiniz; sonraki dosyalar öncekilerde tanımlanan değişkenlerin üzerine yazar. Belgedeki ikinci kural ise daha az bilinir: aynı değişken hem gerçek ortamda hem dosyada tanımlıysa ortamdaki değer kazanır. Bu, sunucuda bir değeri geçici olarak geçersiz kılmak istediğinizde işinize yarar, ama dosyayı değiştirdiğiniz hâlde değerin değişmemesine de yol açabilir.

bash
node --env-file=.env --env-file=.env.local oku.mjs
# çıktı: 4000 string
PORT=9999 node --env-file=.env oku.mjs
# çıktı: 9999 string

İlk komutta .env.local dosyasındaki PORT=4000 değeri .env'deki 3000'i geçersiz kıldı. İkinci komutta kabukta tanımlı PORT=9999 dosyadaki değerin önüne geçti. (Çıktıların yalnızca ilk satırını gösterdik.)

--env-file-if-exists

--env-file dosyayı bulamazsa süreç başlamadan durur. Bizim denememizde ikili "not found" mesajı yazdı ve 9 koduyla çıktı. Dosyanın bazı ortamlarda olup bazılarında olmayacağı durumlar için v22.9.0 ile gelen --env-file-if-exists aynı şekilde çalışır ama dosya yoksa hata vermez. Bu durumda stderr'e bilgi amaçlı bir satır yazıldığını da gördük (çıktıdaki ikili yolunu Linux biçiminde kısalttık):

bash
node --env-file=yok.env oku.mjs; echo "exit=$?"
# çıktı: /usr/local/bin/node: yok.env: not found
# çıktı: exit=9
node --env-file-if-exists=yok.env oku.mjs
# çıktı: yok.env not found. Continuing without it.
# çıktı: undefined undefined
# çıktı: false false

Belgeye göre --env-file, dosyada tanımlanan ve Node.js'i yapılandıran değişkenleri (örneğin NODE_OPTIONS) de ayrıştırıp uygular. Programatik yükleme ise bundan farklı davranır; aşağıda bu ayrıma değiniyoruz.

process.loadEnvFile: kod içinden yükleme

process.loadEnvFile(yol), bir .env dosyasını kodunuzun istediği noktada process.env içine yükler. Yol verilmezse varsayılan './.env''dir; metin, URL veya Buffer kabul eder. Learn rehberi önemli bir farkı vurgular: bu fonksiyon süreç başladıktan sonra çağrıldığı için, dosyada tanımlanan başlangıçla ilgili değişkenlerin (NODE_OPTIONS gibi) süreç üzerinde hiçbir etkisi olmaz; bu değerler yalnızca process.env içinde okunabilir.

javascript
import { loadEnvFile, env } from 'node:process';
import { parseEnv } from 'node:util';
import { readFileSync } from 'node:fs';

console.log(env.PORT);
loadEnvFile();
console.log(env.PORT);
loadEnvFile('.env.local');
console.log(env.PORT);

const ham = readFileSync('.env', 'utf8');
const ayar = parseEnv(ham);
console.log(Object.keys(ayar));
console.log(parseEnv('A=1\nA=2\n B = boşluklu değer \n'));

try {
  loadEnvFile('yok.env');
} catch (err) {
  console.log(err.code);
}
// çıktı: undefined
// çıktı: 3000
// çıktı: 3000
// çıktı: [ 'APP_NAME', 'COKLU', 'DB_HOST', 'DEBUG', 'PORT', 'SIFRE' ]
// çıktı: [Object: null prototype] { A: '2', B: 'boşluklu değer' }
// çıktı: ENOENT

Bu örnekteki üçüncü satıra dikkat edin. .env.local dosyası PORT=4000 içerdiği hâlde loadEnvFile('.env.local') çağrısından sonra değer 3000 olarak kaldı. Denememizde loadEnvFile, process.env içinde zaten tanımlı olan bir değişkenin üzerine yazmadı. Bu, komut satırında birden çok --env-file verdiğinizde sonrakinin kazanmasından farklıdır. Katmanlı ayar dosyaları kullanıyorsanız ya bayrakları tercih edin ya da dosyaları parseEnv ile okuyup birleştirme sırasını kendiniz belirleyin. Olmayan bir dosya için ise ENOENT kodlu bir hata fırlatıldı.

util.parseEnv: yalnızca ayrıştırma

util.parseEnv(icerik), bir .env dosyasının ham içeriğini alır ve değişkenleri bir nesne olarak döndürür; process.env'e dokunmaz. Yukarıdaki örnekte aynı ad iki kez geçtiğinde sonuncunun kazandığını (A: '2') ve tırnaksız değerin çevresindeki boşlukların kırpıldığını görebilirsiniz. Dönen nesnenin prototipi null'dır. Değerler yine metindir: parseEnv('SAYI=0\nBAYRAK=true') sonucunda SAYI: '0' ve BAYRAK: 'true' elde ettik.

parseEnv, ayarları global ortamı kirletmeden bir yapılandırma nesnesine okumak, bir dosyanın içeriğini doğrulamak ya da farklı kaynaklardan gelen değerleri kendi kurallarınızla birleştirmek istediğinizde kullanışlıdır. Örneğin uygulamanız başlarken zorunlu anahtarların hepsinin dosyada bulunup bulunmadığını kontrol edebilir, eksik varsa açıklayıcı bir mesajla çıkabilirsiniz.

Mini örnek: değerleri doğrulayan bir ayar katmanı

Ortam değişkenlerinin hepsi metin olduğu ve eksik olabildiği için, bunları uygulamanın farklı yerlerinde doğrudan process.env.X diye okumak hataları uygulamanın derinliklerine taşır. Daha sağlam bir yol, uygulama başlarken tek bir fonksiyonda tüm değerleri okumak, türlerine çevirmek, doğrulamak ve sonra kodun geri kalanına düz bir nesne vermektir:

javascript
import process from 'node:process';

function ayarlariOku(env) {
  const hatalar = [];
  const port = Number(env.PORT ?? '3000');
  if (!Number.isInteger(port) || port < 1 || port > 65535) hatalar.push(`PORT geçersiz: ${env.PORT}`);
  const debug = env.DEBUG === 'true';
  if (!env.APP_NAME) hatalar.push('APP_NAME tanımlı değil');
  return { ayar: { port, debug, ad: env.APP_NAME }, hatalar };
}

const { ayar, hatalar } = ayarlariOku(process.env);
if (hatalar.length) {
  for (const h of hatalar) console.error(h);
  process.exitCode = 1;
} else {
  console.log(ayar);
}
bash
node --env-file=.env ayar.mjs; echo "kod: $?"
# çıktı: { port: 3000, debug: false, ad: 'Keydal Demo' }
# çıktı: kod: 0
PORT=abc node ayar.mjs; echo "kod: $?"
# çıktı: PORT geçersiz: abc
# çıktı: APP_NAME tanımlı değil
# çıktı: kod: 1

İlk çalıştırmada değerler .env dosyasından geldi; PORT sayıya çevrildi, DEBUG ise yalnızca tam olarak 'true' metni olduğunda true kabul edildi ve dosyadaki 'false' metni doğru biçimde false oldu. İkinci çalıştırmada dosya yüklenmedi ve kabuktan hatalı bir PORT verildi; fonksiyon tüm sorunları tek seferde toplayıp yazdı ve çıkış kodunu 1 yaptı. Fonksiyon process.env yerine bir parametre aldığı için onu test etmek de kolaydır: testte ayarlariOku({ PORT: '80' }) gibi düz bir nesne verebilirsiniz. Bu desen, sunucuya dağıtılan bir uygulamanın eksik ayarla sessizce yanlış çalışması yerine başlangıçta açık bir mesajla durmasını sağlar.

Hangi yöntemi seçmeli?

Hangi yöntemi seçmeli? --env-file, --env-file-if-exists, process.loadEnvFile(), util.parseEnv()
YöntemNe zamanNODE_OPTIONS etkisiDosya yoksa
--env-fileUygulamayı başlatırkenUygulanırBaşlamaz (denememizde kod 9)
--env-file-if-existsDosya isteğe bağlıysaUygulanırUyarı yazıp devam eder
process.loadEnvFile()Kod içinden, koşullu yüklemeEtkisi yokENOENT hatası fırlatır
util.parseEnv()Yalnızca nesneye okumaUygulanmazDosyayı siz okursunuz

Değerlerin metin olduğunu unutmayın ve uygulamanın başında bunları doğru türlere çevirip doğrulayan küçük bir ayar katmanı yazın: Number(env.PORT) sonucu NaN ise ya da DEBUG beklediğiniz değerlerden biri değilse uygulamayı açıklayıcı bir mesajla durdurun. Çıkış kodunu nasıl ayarlayacağınız process.exitCode yazısında anlatılıyor. Ortama göre farklı kod yolları yazmanın neden sorun yarattığını ise Learn rehberinin NODE_ENV bölümünden özetlediğimiz kurulum yazısında bulabilirsiniz.

Sık yapılan hatalar

  • DEBUG=false değerini boolean sanmak: Değer 'false' metnidir ve truthy'dir. Açıkça env.DEBUG === 'true' ile karşılaştırın.
  • Dosyayı değiştirip ortamdaki eski değeri görmek: Aynı değişken kabukta da tanımlıysa ortamdaki değer dosyanın önüne geçer.
  • loadEnvFile ile üzerine yazma beklemek: Denememizde zaten tanımlı değişkenler değişmedi; katmanlı dosyalar için birden çok --env-file kullanın.
  • NODE_OPTIONS'ı loadEnvFile ile ayarlamaya çalışmak: Süreç zaten başladığı için etkisi olmaz.
  • Değişkene undefined atayarak silmek: Değer 'undefined' metni olur; delete process.env.AD kullanın.
  • Windows ve Linux'ta ad büyüklüğünü karıştırmak: Windows'ta Port ile PORT aynı değişkendir, Linux'ta değildir.
  • Geçersiz adlar kullanmak: my-var gibi tire içeren adlar belgedeki kurala uymaz.

Sık Sorulan Sorular

dotenv paketine hâlâ ihtiyacım var mı?

Temel ihtiyaç olan bir .env dosyasını process.env'e yüklemek için yerleşik --env-file ve process.loadEnvFile() yeterlidir ve belgede kararlı olarak işaretlidir. Paketin ek özellikleri Node.js belgelerinin konusu değildir; genel karşılaştırma için .env yazısına bakın.

--env-file yolu nereye göre çözülür?

Belgeye göre geçerli klasöre, yani node komutunu çalıştırdığınız klasöre göre. Betiği başka bir klasörden başlatırsanız mutlak yol verin.

Ortama göre farklı dosya kullanmak için ne yapmalıyım?

Belge, dosya adının genellikle .env olduğunu ya da .env.dev örneğindeki gibi .env ile başlayıp hedef ortamı belirten bir ekle devam ettiğini söyler; bu önerilen bir adlandırmadır ama zorunlu değildir. Ortak değerleri bir dosyada, ortama özgü olanları ikinci bir dosyada tutup --env-file=.env --env-file=.env.dev biçiminde iki bayrakla yükleyebilirsiniz; ikinci dosya ilkinin üzerine yazar. Kabuktan verilen bir değer ise yine ikisinin de önüne geçer.

Worker thread farklı bir ortamla başlatılabilir mi?

Evet. process.env belgesine göre her Worker, aksi belirtilmedikçe ebeveyninin ortamının bir kopyasını alır; Worker kurucusunun env seçeneğiyle farklı bir ortam verebilirsiniz. Windows'ta Worker içindeki kopyanın ana thread'den farklı olarak büyük küçük harfe duyarlı çalıştığını da belge ayrıca not eder.

Değişkenlerin sayı olarak gelmesini sağlayabilir miyim?

Hayır. Node.js tüm değerleri metin olarak okur; dönüşümü kodunuzda yapmanız gerekir.

Hangi ortam değişkenleri Node.js'in kendisini yapılandırır?

NODE_OPTIONS, NODE_DEBUG, NO_COLOR, TZ, UV_THREADPOOL_SIZE gibi değişkenler CLI belgesinin ortam değişkenleri bölümünde listelenir. NODE_OPTIONS için NODE_OPTIONS ve CLI bayrakları yazısına bakın.

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 · .env dosyası nedir · process.argv ve çıkış kodları · node --run · NODE_OPTIONS · worker_threads