Nextjs Environment Variables Runtime Deployment Considerations
Definisi
Di Next.js, environment variables dipakai untuk memisahkan konfigurasi dari kode. Pola ini penting karena nilai yang sama bisa dipakai di lingkungan berbeda: local development, preview, staging, dan production.
Topik ini biasanya menyangkut tiga pertanyaan utama:
- variabel mana yang hanya boleh ada di server
- variabel mana yang aman dipaketkan ke browser
- kapan nilai env dibaca: saat build atau saat runtime
Kalau tiga hal ini dicampur, hasilnya sering terlihat normal di local, lalu pecah setelah deploy.
Perbedaan server-only dan public env vars
Server-only env vars
Server-only env vars adalah variabel yang hanya boleh dipakai di sisi server. Contohnya:
- secret API key
- database URL
- JWT secret
- token untuk service internal
- kredensial pihak ketiga yang tidak boleh bocor ke browser
Di Next.js, variabel seperti ini biasanya diakses lewat process.env.NAMA_VARIABEL dari kode server, misalnya di Server Component, Route Handler, Server Action, atau helper yang hanya dieksekusi di server.
Contoh:
const dbUrl = process.env.DATABASE_URLPrinsipnya sederhana: kalau nilainya sensitif atau punya akses ke sistem backend, jangan pernah dianggap aman untuk client bundle.
Public env vars
Public env vars adalah variabel yang sengaja diekspos ke browser. Di Next.js, pola umumnya memakai prefix NEXT_PUBLIC_.
Contoh:
const analyticsId = process.env.NEXT_PUBLIC_ANALYTICS_IDNilai dengan prefix ini bisa masuk ke JavaScript bundle client saat build. Artinya:
- aman hanya untuk data non-rahasia
- cocok untuk feature flag publik, nama environment, tracking ID, atau endpoint yang memang boleh diketahui user
- tidak cocok untuk secret, walaupun nama variabelnya terdengar “konfigurasi”
Aturan praktisnya:
- kalau user browser boleh melihatnya, pakai public env var
- kalau user browser tidak boleh melihatnya, simpan di server-only env var
Kapan dibaca: build vs runtime
Ini bagian yang paling sering bikin salah paham.
Dibaca saat build
Sebagian env var dibaca saat proses build, lalu nilainya disalin ke hasil bundle atau ke kode yang sudah di-compile. Ini umum untuk:
NEXT_PUBLIC_*yang dipakai di client component- nilai yang diinline oleh bundler saat build
- konfigurasi yang sudah ditentukan sebelum artefak deploy dibuat
Konsekuensinya:
- ganti env var di server setelah build belum tentu mengubah perilaku aplikasi
- rebuild sering dibutuhkan kalau nilai itu dipakai di client bundle
- preview build dan production build bisa menghasilkan perilaku berbeda kalau env-nya beda
Dibaca saat runtime
Env var dibaca saat runtime ketika kode benar-benar berjalan di server. Ini biasanya terjadi pada:
- Server Component
- Route Handler
- Server Action
- helper server-side
- custom server atau runtime Node yang membaca
process.envsaat request datang
Keuntungan runtime read:
- nilai bisa berubah tanpa rebuild, selama platform deployment mendukung runtime env injection
- cocok untuk secret dan konfigurasi server
- lebih aman karena tidak ikut masuk ke browser
Batas pentingnya:
- runtime hanya membantu jika kode itu benar-benar dieksekusi di server
- kalau nilai sudah dipakai untuk membangun client bundle, perubahan runtime tidak akan mengubah bundle yang sudah terbit
Ringkasnya
- Client-side dan
NEXT_PUBLIC_*: biasanya terkunci saat build - Server-side: bisa dibaca saat runtime
- Secret: usahakan selalu server-side
- Config publik: boleh build-time, tapi pahami bahwa hasilnya statik sampai rebuild
Alur build, runtime, dan deploy
Diagram ini menunjukkan kenapa satu variabel bisa berperilaku berbeda tergantung tempat dipakai.
Contoh pola penggunaan
1. Secret hanya di server
// lib/database.ts
export function getDatabaseUrl() {
const url = process.env.DATABASE_URL
if (!url) {
throw new Error('DATABASE_URL belum diset')
}
return url
}Pola seperti ini aman selama fungsi dipanggil dari server-only path.
2. Konfigurasi publik untuk browser
// app/layout.tsx atau client component
const analyticsId = process.env.NEXT_PUBLIC_ANALYTICS_IDPakai ini hanya kalau nilainya memang boleh dilihat publik. Jangan simpan token akses di sini.
3. Validasi awal supaya gagal cepat
const requiredEnv = ['DATABASE_URL', 'JWT_SECRET'] as const
for (const key of requiredEnv) {
if (!process.env[key]) {
throw new Error(`Environment variable ${key} belum diset`)
}
}Validasi seperti ini membantu fail fast saat build atau startup, jadi masalah tidak baru muncul setelah user kena error.
Deployment considerations
1. Preview dan production sering beda env
Platform deployment biasanya memberi environment berbeda untuk branch preview, staging, dan production. Jangan asumsi semua deployment memakai nilai yang sama.
Hal yang perlu dicek:
- apakah preview punya
DATABASE_URLsendiri - apakah production memakai API endpoint yang berbeda
- apakah
NEXT_PUBLIC_*sudah diset di semua environment yang butuh
2. Build-time env harus tersedia saat build
Kalau env dibaca saat build, variabel itu harus sudah ada sebelum command build berjalan.
Kasus umum:
- build di CI gagal karena env belum diinjeksi
- build lokal sukses, deploy gagal karena variable belum ada di platform
- hasil preview memakai nilai lama karena artefak dibangun sebelum env baru dipasang
3. Runtime env harus didukung platform
Tidak semua platform memperlakukan runtime env dengan cara yang sama. Ada yang menyuntikkan env saat container start, ada yang memaketkan nilai lebih awal.
Implikasinya:
- baca dokumentasi platform deploy yang dipakai
- pastikan secret tersedia di runtime environment yang benar
- jangan bergantung pada perubahan env kalau hasil build sudah final dan statik
4. Edge runtime punya batasan berbeda
Kalau route atau middleware berjalan di Edge Runtime, asumsi terhadap process.env dan akses Node.js bisa berbeda dibanding Node runtime.
Artinya:
- jangan mengandalkan library Node yang tidak didukung edge
- cek kompatibilitas env access dan secret handling pada runtime yang dipilih
- pisahkan kode edge-only dan server Node kalau perlu
5. Cache dan rebuild bisa menutupi perubahan env
Perubahan env tidak selalu langsung terlihat karena masih ada:
- cache build
- cache CDN
- cache route/data Next.js
- bundle client yang belum di-rebuild
Kalau mengubah env dan perilaku tidak ikut berubah, cek apakah artefak yang berjalan benar-benar hasil build baru.
Jebakan umum saat deploy
1. Mengira semua process.env dibaca runtime
Ini jebakan paling umum. Tidak semua env tetap dinamis setelah deploy. Kalau sudah diinlin ke client bundle, nilainya ikut build.
2. Meletakkan secret di NEXT_PUBLIC_*
Begitu prefix ini dipakai, anggap nilainya publik. Jangan menyimpan credential, token, atau private key di sana.
3. Mengubah env di platform tanpa rebuild
Kalau variabel dipakai saat build, update env saja tidak cukup. Artefak lama masih membawa nilai lama.
4. Local berhasil, production gagal
Biasanya karena:
.env.localada di laptop, tapi tidak diset di platform- variabel sensitif tidak disalin ke environment production
- build CI tidak memiliki akses ke secret yang sama
5. Mencampur kebutuhan server dan client
Satu variabel dipakai oleh client component dan server helper sekaligus. Akibatnya developer sering “membuka” secret ke client supaya error hilang. Itu solusi yang salah.
Pola yang lebih sehat:
- server membaca secret
- server menyediakan data turunan yang aman ke client
- client hanya menerima hasil olahan, bukan secret mentah
6. Lupa validasi saat startup
Kalau env wajib tidak divalidasi lebih awal, error sering baru muncul saat request pertama datang. Itu bikin debugging lebih mahal.
Checklist praktis
- pisahkan secret server-only dan config publik
- gunakan
NEXT_PUBLIC_*hanya untuk data yang aman dibaca browser - pastikan env build-time sudah ada sebelum
next build - pastikan env runtime tersedia di platform deploy
- cek ulang setelah pindah dari local ke preview atau production
- validasi env wajib saat startup atau build
- jangan anggap perubahan env otomatis mengubah client bundle
Referensi
Catatan implementasi
Kalau topik ini dipakai sebagai pegangan produksi, biasakan melihat dua pertanyaan dulu:
- nilai ini dipakai di server atau client?
- nilainya dibutuhkan saat build atau saat runtime?
Kalau dua pertanyaan itu dijawab dengan benar, sebagian besar bug environment di Next.js biasanya langsung ketahuan sebelum masuk ke production.