Episode ini membahas konfigurasi aplikasi Rust dengan config, dotenv, atau figment, versioning data dan compatibility tipe saat skema berubah, serta praktik separation config per environment dev, staging, dan production.

Aplikasi yang fleksibel tidak meng-hardcode konfigurasi di dalam kode. Host database, key, dan fitur flag seharusnya bisa berubah tanpa rekompilasi. Episode 9 membahas bagaimana aplikasi Rust membaca konfigurasi dari file dan environment, serta bagaimana data bertahan dari perubahan skema.
Kalian akan memakai crate config dan figment untuk menggabungkan banyak sumber konfigurasi, dotenv untuk file .env, memahami versioning API data, dan menerapkan separation config per environment. Ini keterampilan wajib sebelum men-deploy aplikasi ke production.
Environment variables adalah cara paling sederhana dan idiomatis untuk konfigurasi di cloud. File .env mempermudah pengembangan lokal:
DATABASE_URL=postgres://user:pass@localhost/db
PORT=8080
LOG_LEVEL=infodotenvy memuat file ini ke environment process:
cat > src/main.rs <<'EOF'
use std::env;
fn main() {
dotenvy::dotenv().ok();
let port: u16 = env::var("PORT")
.unwrap_or_else(|_| "8080".to_string())
.parse()
.unwrap();
println!("server berjalan di port {}", port);
}
EOF
cargo rundotenvy::dotenv() memuat .env ke environment. env::var("PORT") membaca nilai, dengan fallback 8080 jika tidak ada. Jangan pernah meng-commit .env ke repository — pakai .env.example sebagai templat.
Untuk hierarki yang kompleks, crate config menggabungkan file, environment, dan default:
cat > src/main.rs <<'EOF'
use config::{Config, File, Environment};
fn main() {
let config = Config::builder()
.set_default("host", "127.0.0.1").unwrap()
.add_source(File::with_name("config").required(false))
.add_source(Environment::with_prefix("APP"))
.build()
.unwrap();
let host: String = config.get("host").unwrap();
println!("host: {}", host);
}
EOF
cargo runUrutan sumber menentukan prioritas: default paling rendah, environment paling tinggi. Environment::with_prefix("APP") membaca variabel seperti APP_HOST. Konfigurasi dikumpulkan sekali di awal program dan dibagikan sebagai struct.
figment adalah library konfigurasi yang dipakai kerangka seperti Rocket dan Axum ecosystem. Prinsipnya sama: beberapa layer digabung dengan prioritas jelas.
let config: Config = Figment::new()
.merge(Toml::file("config.toml"))
.merge(Env::prefixed("APP_"))
.extract()?;Env::prefixed("APP_") membaca environment dengan awalan APP_. Layer terakhir menimpa yang sebelumnya. figment menjadi pilihan saat kalian butuh deserialisasi langsung ke struct dengan serde.
Data yang disimpan bertahun-tahun akan menghadapi perubahan skema: field baru, rename, atau perubahan tipe. Database dan file yang disimpan harus tetap bisa dibaca aplikasi lama maupun baru. Dua strategi utama: migrasi untuk database dan versioning payload untuk data terenkode.
Migrasi mencatat perubahan skema secara terurut dan idempotent:
cargo install sqlx-cli --features postgres
sqlx migrate add tambah_kolom_emailIsi file migrasi yang dihasilkan dengan SQL, lalu terapkan:
ALTER TABLE pengguna ADD COLUMN email TEXT;Migrasi dicatat di tabel khusus, sehingga hanya dijalankan sekali. sqlx migrate run memastikan skema semua environment konsisten — ini separuh dari pekerjaan schema evolution.
Untuk data terenkode seperti JSON di database atau event di message queue, tambahkan field versi. Aplikasi baru membaca data lama (forward compatibility), dan aplikasi lama menolak data yang tidak dikenalnya dengan aman:
cat > src/main.rs <<'EOF'
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Event {
v: u32,
nama: String,
}
fn main() {
let lama = r#"{"v":1,"nama":"deploy"}"#;
let event: Event = serde_json::from_str(lama).unwrap();
println!("event v{}: {}", event.v, event.nama);
}
EOF
cargo runField v menandai versi payload. Saat skema berubah, versi dinaikkan dan parser menyesuaikan. Serde juga mendukung #[serde(default)] dan #[serde(alias)] untuk field baru yang opsional serta rename tanpa memecah data lama.
Satu kode, banyak environment: value yang sama di seluruh environment diletakkan di config dasar, sedangkan yang berbeda di-override per environment. Konvensi umum di Rust:
host = "0.0.0.0"
port = 8080
log_level = "info"log_level = "warn"Crate config memilih file berdasarkan environment: APP_ENV=production cargo run menetapkan environment saat menjalankan aplikasi, lalu logika loading menggabungkan file default, file spesifik environment, dan override environment variables. Pola ini menjaga dev, staging, dan production memakai kode yang sama dengan nilai berbeda.
Inti yang harus dibawa pulang:
.env.dotenvy memuat .env; config dan figment menggabungkan banyak sumber.Di episode 10 selanjutnya kita akan membahas networking dasar dan HTTP server — membangun server dengan axum, warp, actix-web, atau hyper, dasar request-response, routing, middleware, dan error handling, serta koneksi TCP dan UDP. Aplikasi kalian mulai berbicara dengan dunia luar.