Ada satu teka-teki kecil yang bikin hampir semua orang bingung di awal. Kamu nulis satu basis kode. Kamu jalankan di laptop, dan dia nyambung ke database di laptopmu. Kamu salin kode yang persis sama itu ke server live, dan entah bagaimana dia malah nyambung ke database yang benar-benar berbeda, pakai password yang berbeda, dan mengarahkan pengguna ke alamat web yang berbeda pula. Tidak ada satu baris pun di kode yang berubah. Jadi, dari mana aplikasinya tahu kumpulan nilai mana yang harus dia pakai?
Jawabannya adalah konfigurasi environment — kebiasaan menaruh semua nilai yang berubah-ubah antar-mesin di luar kode, lalu menyuapkannya dari luar. Begitu ide ini nyantol, segerombolan pusing kepala saat deployment langsung lenyap, dan sebagai bonus aplikasimu jadi jauh lebih aman. Ayo kita susun dari paling dasar.
“Konfigurasi” itu sebenarnya apa
Kalau orang menyebut config, yang mereka maksud adalah setelan yang dibutuhkan programmu untuk berjalan, tapi sebenarnya bukan bagian dari logika program. Coba lihat bedanya dua hal ini:
- Logikanya — “ketika pengguna mendaftar, simpan datanya ke database.” Ini sama di mana pun. Tempatnya di dalam kode.
- Config-nya — database mana yang dipakai untuk menyimpan, password apa yang digunakan, layanan email mana yang dipakai untuk mengirim, situs ini ada di URL apa. Hal-hal ini berubah tergantung di mana aplikasinya berjalan.
Konfigurasi adalah segala sesuatu di keranjang kedua tadi. Dia bukan resep masakannya; dia bahan-bahan spesifik yang kebetulan ada di dapur tertentu ini. Ada satu tes sederhana: kalau sebuah nilai bakal berbeda antara laptopmu dan server production, hampir pasti itu config — bukan kode.
Hal-hal yang umumnya tinggal di config:
- Detail koneksi database (host, port, nama, username, password)
- API key dan token rahasia untuk layanan pihak ketiga
- URL publik atau domain situsmu
- Setelan server email/SMTP
- Feature flag (menyalakan atau mematikan fitur yang masih setengah jadi)
- Nama dari environment yang sedang berjalan itu sendiri (
development,staging,production)
Kenapa config harus di luar kode
Saat baru mulai, godaannya besar untuk langsung mengetik nilai-nilai itu di dalam file sumbermu. Password database ditaruh begitu saja di database.js. Toh jalan di mesinmu, jadi kenapa tidak? Ada tiga alasan kuat untuk tidak melakukannya, dan masing-masing pada akhirnya bakal menggigit.
1. Kode yang sama harus jalan di banyak tempat. Laptopmu, laptop rekan tim, server tes, dan server production live adalah empat environment yang berbeda, masing-masing dengan database dan kredensialnya sendiri. Kalau nilainya tertanam di dalam kode, kamu butuh empat salinan kode yang berbeda — dan lama-lama isinya melenceng satu sama lain, lalu kamu mengirim yang salah. (Kalau istilah “development”, “staging”, dan “production” belum sepenuhnya jelas, tulisan sebelumnya soal environment deployment mengupas tuntas masing-masing dipakai untuk apa.)
2. Rahasia tidak boleh sampai masuk ke version control. Saat kamu meng-commit kode ke Git, riwayat itu abadi dan sering kali dibagikan. Password atau API key yang ditulis langsung di file akan ikut tersalin ke setiap clone, setiap fork, setiap backup. Sudah banyak orang membocorkan kredensial production sungguhan lewat cara ini, lalu akun cloud-nya dikuras dalam hitungan menit oleh bot yang memindai repository publik. Config yang disimpan di luar kode tidak pernah masuk ke riwayat itu sejak awal.
3. Mengubah satu setelan tidak seharusnya berarti mengubah kode. Kalau password database-mu dirotasi, kamu tidak mau harus menyunting file sumber, mengetes ulang, lalu men-deploy seluruh aplikasi cuma demi memperbarui satu string. Dengan config di luar, kamu cukup mengganti nilainya di tempat dia tinggal lalu restart — kodenya sendiri tidak tersentuh.
Kesalahan klasik yang mahal
Insiden keamanan pemula yang paling sering terjadi adalah meng-commit rahasia ke repository publik. Begitu sebuah kunci ter-push — bahkan kalau kamu menghapusnya di commit berikutnya — anggaplah dia sudah bocor dan rotasi (buat yang baru, pensiunkan yang lama). Git mengingat baris yang dihapus di dalam riwayatnya. Solusinya bukan menyapu bersih riwayat lalu berharap aman; solusinya adalah memastikan rahasia tidak pernah ter-commit sejak awal, dan itulah persis yang diberikan oleh konfigurasi environment yang baik.
Environment variable: mekanisme yang berlaku di mana-mana
Jadi kalau config tinggal di luar kode, di mana tepatnya, dan bagaimana kodenya membacanya? Jawaban paling universal — yang berlaku di setiap sistem operasi, di setiap bahasa, di setiap platform hosting — adalah environment variable.
Environment variable hanyalah sebuah nilai bernama yang diserahkan sistem operasi ke sebuah program saat program itu mulai. Programnya bertanya ke OS, “berapa sih nilai DATABASE_URL?” dan OS mengembalikan apa pun yang sudah disetel untuknya. Kodemu tidak pernah memuat nilainya — hanya nama variabel yang ingin dia cari.
Di shell Linux atau macOS standar, kamu menyetelnya seperti ini lalu menjalankan program dalam satu tarikan napas:
# setel variabel khusus untuk satu perintah ini saja
DATABASE_URL="postgres://localhost/myapp_dev" node server.js
# atau export supaya semua perintah di sesi shell ini bisa melihatnya
export DATABASE_URL="postgres://localhost/myapp_dev"
export SECRET_KEY="dev-only-bukan-rahasia-asli"
node server.js
Di dalam program, kamu membacanya lewat nama. Sintaks persisnya tergantung bahasamu, tapi idenya sama di mana-mana:
JavaScript / Node process.env.DATABASE_URL
Python os.environ["DATABASE_URL"]
PHP getenv("DATABASE_URL")
Ruby ENV["DATABASE_URL"]
Go os.Getenv("DATABASE_URL")
Perhatikan kekuatannya di sini: kodenya identik di setiap mesin. Dia selalu cuma minta DATABASE_URL. Yang berbeda adalah nilai yang sudah disetel oleh sistem operasi — myapp_dev di laptopmu, database production sungguhan di server live. Kode sama, environment berbeda, perilaku berbeda. Itulah seluruh triknya.
┌──────────────────────────────────────────┐
│ KODE KAMU (sama di mana-mana) │
│ │
│ db = connect( env["DATABASE_URL"] ) │
└──────────────────┬───────────────────────┘
│ minta nilainya ke OS
┌────────────────┴─────────────────┐
▼ ▼
DI LAPTOP KAMU DI PRODUCTION
DATABASE_URL = DATABASE_URL =
postgres://localhost/dev postgres://prod-host/live
File .env: cara yang lebih ramah untuk mengelolanya
Mengetik export untuk lima belas variabel setiap kali membuka terminal cepat bikin bosan. Solusi yang umum saat development adalah file .env — file teks biasa yang mendaftar variabelmu, satu per baris, dalam bentuk KEY=value:
# .env (tinggal di folder proyekmu, JANGAN PERNAH di-commit)
DATABASE_URL=postgres://localhost/myapp_dev
SECRET_KEY=dev-only-bukan-rahasia-asli
PORT=3000
SMTP_HOST=localhost
FEATURE_NEW_CHECKOUT=false
Sebuah library kecil di bahasamu (atau fitur bawaan framework-mu) membaca file ini saat aplikasi menyala dan memuat tiap baris ke dalam environment, persis seolah-olah kamu meng-export-nya satu per satu dengan tangan. Dari sudut pandang kodemu, tidak ada yang berubah — dia tetap cuma membaca env["DATABASE_URL"]. File .env murni soal kemudahan untuk menyetel nilai-nilai itu di satu tempat yang rapi.
Satu aturan yang tidak boleh kamu langgar: file .env tidak ikut masuk version control. Tambahkan ke .gitignore segera, bahkan sebelum kamu membuat file-nya. Lalu, supaya rekan tim tahu variabel apa saja yang ada tanpa melihat rahasia aslimu, commit-lah sebuah file contoh sebagai gantinya:
# .env.example (yang ini IKUT di-commit — nilainya kosong atau palsu)
DATABASE_URL=
SECRET_KEY=
PORT=3000
SMTP_HOST=
FEATURE_NEW_CHECKOUT=false
Developer baru tinggal menyalin .env.example jadi .env, mengisi nilai sungguhan, dan langsung jalan — tanpa siapa pun harus berbagi rahasia live lewat Git.
Nama itu bercerita — pakai konvensi
Nama environment variable ditulis dalam UPPER_SNAKE_CASE sesuai konvensi yang sudah lama dipakai, jadi DATABASE_URL, bukan databaseUrl. Buat namanya deskriptif dan kelompokkan lewat awalan bila membantu — SMTP_HOST, SMTP_PORT, SMTP_USER terbaca sebagai satu keluarga yang jelas. Skema penamaan yang konsisten membuat .env.example-mu sekaligus berfungsi sebagai dokumentasi: rekan baru bisa melirik sekilas dan langsung paham semua yang dibutuhkan aplikasi untuk berjalan.
Bedanya config antar-environment
Inti dari semua ini adalah tiap environment mencolokkan nilainya sendiri. Bentuk config-nya (daftar nama variabelnya) tetap sama; hanya nilainya yang berubah. Ini aplikasi yang sama di tiga tempat:
VARIABEL DEVELOPMENT STAGING PRODUCTION
─────────────────────────────────────────────────────────────────────────────
DATABASE_URL localhost/myapp_dev staging-db/myapp prod-db/myapp
SECRET_KEY dev-palsu (kunci staging asli) (kunci prod asli)
SITE_URL http://localhost:3000 https://staging.site https://www.site
LOG_LEVEL debug info warn
SEND_REAL_EMAILS false false true
ENVIRONMENT development staging production
Ada beberapa hal yang layak diperhatikan di tabel itu. Baris development sengaja memakai rahasia palsu dan database lokal — tidak ada hal sungguhan yang boleh menyentuh laptop seorang developer. Flag SEND_REAL_EMAILS mati sampai production, jadi pengetesan tidak akan tak sengaja mengirim email ke pelanggan sungguhan. Lalu LOG_LEVEL lebih cerewet di development (di mana kamu ingin melihat segalanya) dan lebih senyap di production (di mana kebisingan itu mahal dan justru menyembunyikan masalah nyata). Kode yang sama membaca LOG_LEVEL di mana-mana; nilainyalah yang menentukan perilakunya.
Satu variabel pantas disebut khusus: yang menamai environment yang sedang berjalan, sering disebut NODE_ENV, APP_ENV, atau cukup ENVIRONMENT. Kode dan framework-mu kerap mengeceknya untuk memutuskan hal-hal seperti apakah perlu menampilkan halaman error yang detail (membantu di development, jadi celah keamanan di production) atau apakah perlu melakukan caching secara agresif. Menyetelnya dengan benar per environment itu sepele tapi penting.
Dari mana sebenarnya nilai production datang
Kalau kamu tidak pernah meng-commit file .env, ada pertanyaan yang wajar: bagaimana nilai yang benar bisa sampai ke server production, di mana tidak ada developer yang mengetik export? Umumnya ada tiga pilihan, dan tim sungguhan biasanya mencampur ketiganya.
- Setel di server / platform. Sebagian besar platform hosting dan process manager mengizinkanmu mendefinisikan environment variable lewat dashboard atau konfigurasinya, terpisah dari kodemu. Platform menyuntikkannya ke aplikasimu saat menyala. Ini pendekatan paling bersih untuk hosting cloud — rahasia tinggal di platform, tidak pernah di repo.
- File
.envyang diletakkan di server secara manual atau lewat proses deploy. File-nya cuma ada di mesin itu, dibuat saat deployment, dengan izin berkas yang ketat supaya hanya user aplikasimu yang bisa membacanya. Dia tetap tidak pernah masuk Git; dia disalin atau dibuat saat deploy. - Secrets manager khusus. Untuk setup yang lebih besar atau lebih sensitif keamanannya, ada layanan terpisah yang menyimpan rahasia, mengatur siapa yang boleh membacanya, dan mencatat setiap akses. Aplikasi mengambil config-nya dari sana saat startup. Ini berlebihan untuk proyek kecil, tapi jadi standar di skala besar.
Pilihan mana pun yang kamu ambil, aturan emasnya tetap berlaku: nilainya sampai ke proses yang sedang berjalan sebagai environment variable, kodenya membacanya dengan cara universal yang sama, dan rahasianya sendiri tidak pernah tinggal di dalam kode sumber.
Config erat kaitannya dengan environment variable secara umum
Semua yang dibahas di sini adalah sudut pandang deployment dari sebuah konsep Linux/OS yang lebih umum. Kalau kamu mau gambaran tingkat yang lebih rendah — bagaimana sistem operasi menyimpan variabel-variabel ini, bagaimana export dan sesi shell sebenarnya bekerja, serta bagaimana proses anak mewarisinya — artikel khusus soal environment variable di bagian Linux mengupas satu lapis lebih dalam daripada yang kita butuhkan di sini.
Beberapa kebiasaan yang menyelamatkanmu dari pusing
Tidak ada yang rumit di sini, tapi segelintir kebiasaan memisahkan setup yang mulus dari yang bocor dan rapuh:
.gitignorefile.envlebih dulu, setiap kali. Jadikan ini hal pertama yang kamu lakukan di proyek baru, sebelum ada rahasia yang mungkin menyelip masuk.- Commit
.env.exampledengan nilai kosong atau palsu. Dia mendokumentasikan apa yang dibutuhkan dan membuat rekan tim bisa langsung mulai tanpa tukar-menukar password lewat jalur samping. - Jangan pernah nge-log rahasia. Gampang banget tak sengaja mencetak seluruh config-mu ke file log saat sedang debugging. Log itu dibagikan dan disimpan; perlakukan seakan-akan siapa pun bisa membacanya.
- Gagal dengan keras kalau ada variabel wajib yang hilang. Buat aplikasimu mengecek saat startup bahwa variabel yang dia butuhkan memang ada, dan menolak menyala dengan pesan error yang jelas kalau salah satunya tidak ada. Crash saat startup jauh lebih baik daripada kegagalan misterius jam 3 pagi.
- Rotasi apa pun yang bocor. Kalau sebuah rahasia sampai ke tempat yang tidak seharusnya — sebuah commit, chat, screenshot — buat yang baru lalu pensiunkan yang lama. Anggap yang bocor itu sekarang sudah jadi milik publik.
Penutup
Ini seluruh idenya dalam satu tempat:
- Konfigurasi adalah segala sesuatu yang dibutuhkan aplikasimu yang berubah dari mesin ke mesin — detail database, kunci, URL, flag — berbeda dengan logika, yang tetap sama.
- Config harus tinggal di luar kode supaya satu basis kode bisa jalan di banyak environment, supaya rahasia tidak pernah masuk version control, dan supaya mengganti satu setelan tidak berarti mengganti kode.
- Environment variable adalah cara universal untuk menyuapkan config: kode membaca sebuah nilai lewat nama dari sistem operasi, dan nilai itu berbeda per environment sementara kodenya tetap identik.
- File
.envadalah cara yang praktis untuk menyetel variabel-variabel itu saat development — tapi dia harus di-git-ignore, dipasangkan dengan template.env.exampleyang ikut di-commit, yang membawa nama tapi tanpa rahasia sungguhan. - Di production, nilainya datang dari platform hosting, sebuah file di sisi server, atau secrets manager — tidak pernah dari repository.
- Bangun kebiasaan aman sejak dini: ignore
.env, jangan pernah nge-log atau meng-commit rahasia, gagal dengan keras saat variabel hilang, dan rotasi apa pun yang bocor.
Dengan konfigurasi yang tertangani rapi, aplikasimu jadi portabel dan rahasiamu aman — dan justru itulah pijakan yang kamu mau sebelum perhatian deployment besar berikutnya: memastikan sebuah domain sungguhan melayani lalu lintas dengan aman lewat HTTPS, dan di situlah sertifikat SSL dalam praktik masuk ke gambar.