Konfigurasi aplikasi Node mencakup nilai yang berbeda per lingkungan, seperti porta server, tingkat log, dan string koneksi basis data, serta nilai yang bersifat rahasia seperti kunci API dan kata sandi. Konfigurasi dipisahkan dari kode sumber dengan memasoknya lewat variabel lingkungan, sehingga kode tetap sama antara lingkungan dev, staging, dan produksi, sedangkan nilai yang berbeda dipasok dari luar. Setelah membaca topik ini, pembaca dapat membaca konfigurasi dari process.env, menyusunnya menjadi objek terstruktur dengan nilai default dan konversi tipe, memuat berkas .env pada lingkungan pengembangan, dan menjaga rahasia tetap di luar kontrol versi.
Berkas env dan pola twelve-factor#
Variabel lingkungan adalah sarana konfigurasi utama yang memisahkan nilai dari kode sumber. Node memasok seluruh variabel lingkungan proses melalui objek global process.env, dan nilainya selalu bertipe string atau undefined. Konsekuensi tipe ini adalah konversi eksplisit diperlukan untuk angka dan boolean. String "8080" tidak dapat dipakai langsung sebagai porta pada server.listen yang meminta angka, dan string "false" tetap dianggap true bila dievaluasi sebagai boolean sebab string tidak kosong selalu truthy.
Berkas .env berisi pasangan NAMA=nilai dan lazim dipakai pada lingkungan pengembangan agar pembaca tidak perlu mengetik variabel lingkungan pada setiap pemanggilan node. Berkas ini tidak dimuat otomatis oleh Node, sehingga memerlukan paket seperti dotenv atau fitur bawaan Node sejak versi 20.6 yang memuat .env dengan opsi --env-file. Pada produksi, berkas .env jarang dipakai karena nilai konfigurasi dipasok oleh runner proses, orchestrator kontainer, atau layanan manajemen rahasia, bukan oleh berkas yang ikut masuk paket deploy.
NODE_ENV=development
APP_PORT=3000
APP_LOG_LEVEL=info
APP_DB_URL=postgres://localhost:5432/app_dev
APP_JWT_SECRET=ganti-dengan-string-acak-yang-panjangBerkas .env.example di atas berfungsi sebagai dokumentasi variabel yang diperlukan aplikasi, tanpa memuat nilai rahasia. Berkas ini aman dimasukkan ke kontrol versi agar pengembang baru tahu variabel apa yang perlu dipasok. Berkas .env yang berisi nilai asli tidak boleh masuk kontrol versi, sebab memuat kredensial yang berlaku pada lingkungan tertentu.
Konfigurasi sebagai objek terstruktur#
Membaca process.env langsung di banyak tempat pada kode membuat aplikasi sulit diuji dan mudah membocorkan nilai default yang berbeda antar modul. Praktik yang lebih disiplin adalah membaca seluruh variabel lingkungan sekali pada modul konfigurasi tunggal, lalu mengekspor objek terstruktur yang dipakai modul lain. Modul ini juga tempat untuk menetapkan nilai default, melakukan konversi tipe, dan menandai flag seperti isProduction yang diturunkan dari NODE_ENV.
const config = {
port: Number(process.env.APP_PORT) || 3000,
nodeEnv: process.env.NODE_ENV || 'development',
logLevel: process.env.APP_LOG_LEVEL || 'info',
isProduction: process.env.NODE_ENV === 'production',
dbUrl: process.env.APP_DB_URL || 'postgres://localhost:5432/app_dev'
};
console.log('konfigurasi:');
console.log(JSON.stringify(config, null, 2));konfigurasi:
{
"port": 3000,
"nodeEnv": "development",
"logLevel": "info",
"isProduction": false,
"dbUrl": "postgres://localhost:5432/app_dev"
}Keluaran di atas dihasilkan ketika skrip dijalankan tanpa variabel lingkungan tambahan, sehingga seluruh nilai default dipakai. Konversi Number(process.env.APP_PORT) menghasilkan angka karena APP_PORT tidak diset dan Number(undefined) mengembalikan NaN, yang oleh operator || dianggap falsy sehingga diganti dengan 3000. Untuk memeriksa perilaku ketika variabel lingkungan dipasok, jalankan skrip yang sama dengan variabel yang eksplisit.
# jalankan dengan konfigurasi produksi
APP_PORT=8080 NODE_ENV=production APP_LOG_LEVEL=debug \
APP_DB_URL=postgres://db.local:5432/app_prod node config.jskonfigurasi:
{
"port": 8080,
"nodeEnv": "production",
"logLevel": "debug",
"isProduction": true,
"dbUrl": "postgres://db.local:5432/app_prod"
}Variabel yang dipasok pada awal perintah menggantikan seluruh nilai default, sehingga port menjadi 8080 dan isProduction menjadi true karena NODE_ENV bernilai 'production'. Pola ini menunjukkan bahwa kode sumber tidak perlu diubah ketika konfigurasi berubah, sebab perbedaan ditangani oleh variabel lingkungan yang dipasok dari luar.
Memuat berkas env dengan dotenv#
Pada lingkungan pengembangan, mengetik variabel lingkungan pada setiap pemanggilan node menjadi repitisi yang melelahkan. Paket dotenv memuat berkas .env pada direktori kerja dan menempatkan pasangannya ke process.env sebelum kode aplikasi berjalan. Pemanggilan require('dotenv').config() cukup dilakukan sekali pada titik masuk aplikasi, biasanya berkas src/index.js atau server.js. Modul yang diimpor setelah pemanggilan ini langsung melihat variabel lingkungan yang baru, sehingga urutan pemuatan menjadi penting dan modul dotenv harus menjadi impor pertama pada berkas titik masuk.
Sejak Node 20.6, opsi --env-file=.env pada CLI node memuat berkas .env tanpa paket tambahan. Opsi ini lebih disukai pada proyek baru karena mengurangi dependensi dan menempatkan pemuat env pada level runtime, sehingga kode aplikasi tidak perlu tahu bahwa berkas .env dipakai. Opsi --env-file juga mendukung beberapa berkas dengan urutan eksplisit, yang berguna untuk memisahkan .env umum dan .env.local yang berisi penggantian per pengembang. Variabel yang dideklarasikan pada berkas pada urutan awal dapat ditimpa oleh berkas pada urutan belakang, sehingga pengembang dapat menimpa nilai tim tanpa mengubah berkas bersama.
Disiplin rahasia#
Rahasia seperti kunci API, kata sandi basis data, dan kunci penandatanganan token harus tetap berada di variabel lingkungan dan tidak boleh ditanam pada kode sumber, dicetak ke log, atau ditulis ke berkas yang masuk kontrol versi. Disiplin ini mencegah kebocoran ketika kode sumber dibagikan, diunggah ke registry paket, atau diinspeksi pada alat pelacakan error.
Daftar berikut merangkum praktik yang menjaga rahasia tetap terisolasi:
- Berkas
.envyang berisi nilai asli ditambahkan ke.gitignore, sedangkan.env.exampletanpa nilai rahasia dimasukkan ke kontrol versi sebagai dokumentasi. - Log aplikasi tidak mencetak objek konfigurasi secara penuh, sebab
console.log(config)dapat membocorkandbUrldan kunci lainnya ke alat pengumpul log. - Pesan error yang dibangkitkan dari kegagalan koneksi atau autentikasi tidak menyertakan string koneksi atau kata sandi pada konteksnya.
- Variabel rahasia dipasok ke proses anak sebagai variabel lingkungan eksplisit, bukan sebagai argumen baris perintah, sebab argumen baris perintah terlihat pada
ps auxdan alat sejenis.
Kesalahan umum#
Penanganan boolean dari variabel lingkungan adalah sumber bug yang sering muncul. Ekspresi if (process.env.APP_DEBUG) menganggap string kosong sebagai false tetapi string 'false' sebagai true, sebab string non-kosong selalu truthy pada JavaScript. Pembandingan eksplisit seperti process.env.APP_DEBUG === '1' memberikan hasil yang sesuai harapan dan tidak ambigu. Variabel yang memerlukan konversi boolean sebaiknya dibaca pada modul konfigurasi dengan pembandingan eksplisit, sehingga modul lain menerima boolean asli dan tidak perlu mengulang konversi.
Kesalahan lain adalah menempatkan nilai default yang berbeda antar modul. Modul server.js mungkin memakai process.env.APP_PORT || 3000, sedangkan modul client.js memakai process.env.APP_PORT || 4000. Akibatnya, klien menghubungi porta 4000 padahal server mendengarkan porta 3000. Pemusatan pembacaan variabel lingkungan pada modul konfigurasi tunggal menghilangkan inkonsistensi ini, sebab nilai default hanya ditetapkan sekali dan dibagikan ke seluruh modul yang membutuhkan.
Ringkasan#
- Variabel lingkungan dipasok lewat
process.envsebagai string atauundefined, sehingga konversi ke angka memakaiNumber(...)dan ke boolean memakai pembandingan eksplisit seperti=== 'production'. - Konfigurasi dipusatkan pada satu modul yang membaca
process.env, menetapkan nilai default, dan mengekspor objek terstruktur agar modul lain tidak perlu membaca variabel lingkungan secara langsung. - Berkas
.envdipakai pada lingkungan pengembangan dan dimuat lewat paketdotenvatau opsi--env-filepada Node 20.6 ke atas, sedangkan produksi memasok variabel dari runner proses atau layanan manajemen rahasia. - Rahasia tidak boleh ditanam pada kode sumber, dicetak ke log, atau dimasukkan ke kontrol versi, dan
.envyang berisi nilai asli ditambahkan ke.gitignore.
Referensi#
- Environment variables — Node.js
— Dokumentasi resmi properti
process.envbeserta perilaku tipe string dan cara mengubahnya. - dotenv — GitHub
— Repositori sumber paket
dotenvdengan dokumentasi opsipath,override, dan konfigurasi pemuatan berkas.env. - Node.js 20.6.0 release — Node.js
— Pengumuman rilis yang memperkenalkan opsi
--env-filebawaan Node untuk memuat berkas.envtanpa paket tambahan.