Pada series ini aku akan membahas apa itu Nix, NixOS, dan bagaimana menggunakan NixOS di server. Nix punya cara berpikir yang cukup berbeda dari package manager pada umumnya, jadi kita mulai dari dasarnya dulu.
Sedikit Sejarah Nix
Nix dikenalkan oleh Eelco Dolstra, seorang peneliti asal Belanda yang mana ia frustasi dengan cara kerja package manager yang tidak bisa menjamin konsistensi software environment. Analogi permasalahan yang coba diselesaikan oleh Dolstra sederhananya seperti ini, bayangkan kamu sedang mengerjakan sebuah project di komputermu dan semuanya berjalan lancar. Lalu kamu pindah ke komputer lain, menginstal ulang semua dependency yang kamu butuhkan dan tiba-tiba terjadi error. Error bermunculan saat install dependency, padahal kamu sudah melakukan hal yang sama persis di komputer sebelumnya. Masalah ini sering terjadi dengan sebutan "works on my machine".
Dolstra mengerjakan Nix sebagai bagian dari disertasi PhD-nya yang dipublikasikan pada 2006, berjudul "The Purely Functional Software Deployment Model". Tesis ini membahas tentang bagaimana cara deploy sebuah software yang reliable, di mana input yang sama selalu menghasilkan output yang sama. Nix pertama kali dirilis pada 2003 sebagai bagian dari riset tersebut, dan kini telah berkembang menjadi ekosistem dengan lebih dari 100.000 package.
Apa itu nix
Saat pertama kali mendengar nix beberapa orang pasti bingung karena nix bisa merujuk ke beberapa konteks sekaligus, nah pada artikel ini kita akan berkenalan dengan nix.
- Sebagai Bahasa Pemrograman: Nix adalah functional programming language yang digunakan untuk menulis konfigurasi secara deklaratif. Gimana maksudnya? Sederhananya seperti ini, jika kita menggunakan OS linux seperti ubuntu, debian, arch, dll., untuk installasi sebuah package kita harus menjalankan perintah
apt-get installataupacmandan disetiap package yang sudah kita install, lokasi file konfigurasi berada ditempat yang berbeda-beda. Dengan menggunakan nix kita tidak perlu melakukan installasi dan konfigurasi sebuah package secara imperative, kita hanya perlu mendeklarasikan package dan konfigurasi yang kita butuhkan lalu di evaluasi. - Sebagai Package Manager: Nix adalah package manager yang mengevaluasi seluruh konfigurasi pada file
.nix. Berbeda dengan package manager lainnya sepertiaptataupacman. Nix menyimpan semua package secara isolate di/nix/store - Sebagai OS: NixOS adalah linux distribution yang menggunakan nix sebagai package manager yang dikelola secara deklaratif, seluruh konfigurasi sistem pun ditulis dalam nix language, mulai dari networking, user, service, sampai bootloader.
Sekarang kita sudah tahu bahwa "Nix" bukan satu hal: ia adalah bahasa, package manager, sekaligus OS. Untuk memahami kenapa tiga hal ini bisa menyatu, kita perlu melihat bagaimana Nix bekerja di balik layar.
Bagaimana Nix bekerja
Masalah dengan package manager
Ketika kamu menginstal software dengan apt install atau brew install, biasanya file-file program ini ditempatkan di lokasi standar seperti /usr/lib/ atau /usr/bin/. Ini terlihat tertata dengan rapi, tapi dapat menimbulkan masalah dikemudian hari. Contoh masalah yang bisa saja terjadi adalah dependency hell, sebuah situasi dimana dua aplikasi butuh versi library yang berbeda tapi tidak bisa berjalan secara bersamaan
Situasi bermasalah: "Dependency Hell"
Aplikasi A ──────────────► butuh Python 3.8
│
FILE DI /usr/lib/python3.8/
│
Aplikasi B ──────────────► butuh Python 3.11
│
⚠️ KONFLIK!
Tidak bisa dua versi
di tempat yang sama!
Solusi Nix: Storage Khusus di /nix/store
Nix mengatasi masalah ini dengan pendekatan yang berbeda. Setiap package disimpan di direktori khusus: /nix/store. Yang membuatnya unik adalah setiap package memiliki nama folder yang berisi hash, semacam identifier unik berdasarkan isi package itu sendiri.
/nix/store/
│
├── 9xgd3k2lmn7pqrs123abc456def7890z-firefox-120.0/ ← Firefox versi 120
│ ├── bin/firefox
│ └── lib/...
│
├── 7hqw8p9rst456mnop789qrs012tuv3456-firefox-119.0/ ← Firefox versi 119
│ ├── bin/firefox (bisa hidup berdampingan!)
│ └── lib/...
│
├── 2abc4d5efg789wxyz012345abc678def90-python-3.8.18/ ← Python 3.8
│ └── lib/...
│
└── 5jkl6m7nop012ghi345jkl678mno9012p-python-3.11.6/ ← Python 3.11
└── lib/... (keduanya ada sekaligus!)
Dua versi Python, dua versi Firefox; semuanya bisa diinstall dan digunakan tanpa konflik, karena masing-masing punya identifier yang unik.
Sistem Hash: Unique Signature Build
Hash sebagai unique identifier (deretan 32 karakter seperti 9xgd3k2lmn7pqrs123abc456def7890z) ini dihitung dari seluruh definisi pembuatan package mulai dari: source code, dependency, compiler yang digunakan, bahkan environment variable yang dipakai saat build. Jika ada satu hal yang berbeda maka hashnya akan berbeda juga.
┌─────────────────────────────────────────────────────────────┐
│ CARA NIX MEMBERI NAMA SEBUAH PACKAGE │
│ │
│ Input: │
│ ┌─────────────────────────────────┐ │
│ │ • Source code Firefox 120.0 │ │
│ │ • Versi GCC yang dipakai │ ──► HASH ── │
│ │ • Semua library dependency-nya │ 9xgd3k2l... │
│ │ • Versi library-library itu │ (32 karakter) │
│ └─────────────────────────────────┘ │
│ │
│ Hasilnya: │
│ /nix/store/9xgd3k2lmn7pqrs123abc456def7890z-firefox-120.0/ │
│ │
│ Ubah SATU hal kecil → hash BERBEDA → │
│ folder BERBEDA → tidak akan pernah bentrok! │
└─────────────────────────────────────────────────────────────┘
Ini disebut content-addressed storage. Jika apapun berubah dari inputs → hashnya berbeda → path di store berbeda → package yang berbeda.
Karena hash inilah yang membuat nix menjamin reproducibility.
Reproducible Builds: Kunci Utama Nix
Inilah keunggulan terbesar Nix: reproducibility.
Karena setiap package dibuild dari definisi yang deterministic, siapapun yang menjalankan build yang sama akan mendapat hasil yang identik, di komputer mana pun.
Tanpa Nix:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Laptop A │ │ Laptop B │ │ Server │
│ Python │ │ Python │ │ Python │
│ 3.11.2 │ ≠ ≠ ≠ │ 3.11.6 │ ≠ ≠ ≠ │ 3.11.8 │
│ pip 22.x │ │ pip 23.x │ │ pip 24.x │
│ numpy │ │ numpy │ │ numpy │
│ 1.24.0 │ │ 1.25.1 │ │ 1.26.0 │
└──────────┘ └──────────┘ └──────────┘
"Works on my machine!" 😩
─────────────────────────────────────────────────────
Dengan Nix:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Laptop A │ │ Laptop B │ │ Server │
│ Python │ │ Python │ │ Python │
│ 3.11.6 │ = = = │ 3.11.6 │ = = = │ 3.11.6 │
│ numpy │ │ numpy │ │ numpy │
│ 1.25.1 │ │ 1.25.1 │ │ 1.25.1 │
└──────────┘ └──────────┘ └──────────┘
Works perfectly! ✅
Binary vs Source: Bagaimana Nix Memutuskan?
Saat kamu menggunakan nix dan melakukan installasi sebuah package, kamu bisa melihat ada proses copy atau build from source pada package tersebut. Nix tidak selalu melakukan build dari source dan nix memiliki mekanisme yang disebut substituters (atau binary cache).
Nix evaluate expression → dapat hash/
└── Nix lookup ke binary cache: "Ada /nix/store/<hash>-nodejs-20.11.0 ?"/
├── Ada → Download binary langsung (substitute)
└── Tidak ada → Build dari source secara lokal
Default binary cache untuk NixOS/nixpkgs adalah cache.nixos.org yang dimanage oleh Hydra (Nix's CI system). Hydra secara otomatis build semua package di nixpkgs dan menyimpan hasilnya ke cache, sehingga mayoritas package populer sudah tersedia sebagai binary dan tidak perlu di-build ulang dari source.
Perlu dicatat: jika kamu menggunakan nixpkgs-unstable (channel yang lebih baru), ada kemungkinan binary cache untuk package tertentu belum tersedia karena Hydra belum selesai build-nya, sehingga Nix akan fall back ke build dari source secara lokal.
Alasan Nix Lebih Unggul dari Package Manager Lain
Tidak ada lagi “Dependency Hell”
Seperti yang sudah dijelaskan diatas, Nix memungkinkan berbagai versi package terinstall secara bersamaan. Dengan apt atau brew, kamu tidak bisa melakukan installasi secara native untuk dua package dengan versi yang berbeda.
Bisa Rollback sistem
Saat melakukan upgrade sistem, Nix tidak langsung menggantikan package yang sudah terinstall. Sebaliknya, Nix membangun generation baru yang berisi versi package yang sudah diperbarui, sementara generation lama tetap utuh di sistem.
Setiap kali kamu menjalankan perintah berikut, Nix secara otomatis membuat generation baru:
# NixOS
sudo nixos-rebuild switch
# Nix Darwin
sudo darwin-rebuild switch
Konsep generation inilah yang membuat Nix aman untuk diupgrade. Jika sesuatu berjalan tidak semestinya setelah upgrade, kamu bisa rollback ke generation sebelumnya tanpa perlu reinstall atau konfigurasi ulang apapun. Cukup dengan satu command atau memilih generation dari boot menu:
# Rollback ke generation sebelumnya
sudo nixos-rebuild switch --rollback
# Atau pilih generation spesifik dari daftar
nix-env --list-generations
nix-env --switch-generation 2
Berikut ilustrasinya:
Riwayat "generasi" sistemmu:
gen 1 gen 2 gen 3 (sekarang)
┌────────┐ ┌────────┐ ┌────────┐
│Firefox │ │Firefox │ │Firefox │
│ 118 │ │ 119 │ │ 120 │
│Python │ │Python │ │Python │
│ 3.10 │ │ 3.10 │ │ 3.11 │
└────────┘ └────────┘ └────────┘
▲ │
│ │ ada yang salah?
└────────────────┘
rollback → kembali ke gen 2
atau pilih gen 1 dari boot menu!
Development Environment yang Terisolasi
Nix memiliki fitur nix develop dan nix shell yang memungkinkan kita untuk membuat development environment yang terisolasi per-project, mirip virtualenv di python atau node_modules di Node.js.
Project A butuh Node 18 + PostgreSQL 14:
$ cd project-a && nix develop
→ Masuk environment: Node 18, PostgreSQL 14 ✓
Project B butuh Node 20 + PostgreSQL 16:
$ cd project-b && nix develop
→ Masuk environment: Node 20, PostgreSQL 16 ✓
Keduanya terisolasi, tidak saling mengganggu
Environment ini didefinisikan dalam file flake.nix (cara modern) atau shell.nix (cara lama). Dengan Nix Flakes (fitur yang kini menjadi standar de facto), kamu bisa mendefinisikan seluruh dependency project dalam satu file flake.nix yang ter-lock (mirip package-lock.json di Node.js), sehingga siapapun yang clone project tersebut akan mendapat environment yang sama persis.
# Contoh flake.nix sederhana
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system}; in {
devShells.default = pkgs.mkShell {
packages = [ pkgs.nodejs_20 ];
};
}
);
}
Tidak Mengotori Sistem
Berbeda dengan package manager konvensional, Nix menyimpan setiap package di lokasi terisolasi di bawah /nix/store. Tidak ada file yang tersebar ke berbagai direktori sistem seperti /usr/lib atau /etc.
Dengan struktur penyimpanan yang terisolasi seperti ini, Nix tahu persis mana yang masih dibutuhkan dan mana yang sudah tidak. Jadi saat kamu menjalankan nix-collect-garbage, hanya package yang benar-benar tidak dibutuhkan oleh siapapun yang akan dihapus. Tidak ada file sisa (leftover) yang tertinggal di sudut-sudut sistem, seperti yang sering terjadi setelah apt remove di Ubuntu.
Penutup
Dependency hell sudah jadi masalah lama di dunia software, dan Nix adalah salah satu jawaban tepat untuk masalah tersebut. Lahir dari frustasi nyata seorang peneliti pada 2003, Nix kini telah berkembang menjadi ekosistem yang mencakup lebih dari 100.000 package, dengan komunitas yang aktif dan terus bertumbuh.
Empat hal yang perlu diingat:
- Nix adalah bahasa untuk mendeskripsikan software secara deklaratif.
-
Nix adalah package manager yang menyimpan setiap package secara terisolasi di
/nix/store. - Reproducibility: build yang sama menghasilkan output yang identik di mesin mana pun.
- NixOS adalah OS di mana seluruh konfigurasi sistem (dari networking hingga bootloader) ditulis dalam Nix language.
Learning curve Nix memang curam, dan bagian terberatnya bukan di syntax melainkan perubahan mental model dari imperatif ke deklaratif. Tapi kabar baiknya: begitu kamu "klik" dengan cara berpikirnya, kamu akan sulit kembali ke cara lama. Di artikel berikutnya, kita akan menginstall NixOS di VirtualBox sebagai langkah awal yang aman untuk bereksperimen.

Top comments (0)