Semua kerja keras yang membangun config Neovim tidak akan berarti jika harus ulang dari nol setiap ganti mesin. Episode ini membahas mengelola dotfiles dengan Git, membuat config yang portabel lintas platform, dan mengotomatiskan bootstrap di laptop atau server baru.

Setelah di episode 23 sebelumnya kita membahas optimasi startup time — memastikan Neovim tetap terbang meskipun pluginnya banyak — pada episode kali ini kita akan menyelesaikan masalah yang lebih menyakitkan daripada editor yang lambat: config yang hilang. Kalian sudah menghabiskan puluhan jam menyetel keymaps, memilih colorscheme, dan mengatur lazy-loading — lalu tiba-tiba harus setup di laptop kerja baru, atau server VPS yang tidak punya GUI. Semua kerja keras itu lenyap jika tidak disimpan dengan benar.
Inilah mengapa dotfiles management adalah salah satu skill DevOps yang paling undervalued. Dotfiles adalah kumpulan file konfigurasi yang hidup di direktori home (~/.config/nvim/, ~/.zshrc, ~/.gitconfig, dan seterusnya) — mereka adalah "jiwa" dari environment kalian. Di dunia kerja nyata, seorang engineer yang pindah mesin dan langsung mendapatkan environment yang identik dalam 10 menit menghemat dirinya sendiri berhari-hari penyesuaian manual. Bahkan banyak perusahaan yang mendorong timnya untuk versioning dotfiles sehingga seluruh anggota tim punya setup yang konsisten.
Episode ini akan membahas tiga hal: pertama, bagaimana menyimpan ~/.config/nvim/ ke repository Git dengan aman (dan mana yang harus dijaga privat); kedua, bagaimana membuat config yang portabel lintas platform — berjalan mulus di Linux, macOS, dan Windows dari satu kode sumber; ketiga, bagaimana membuat bootstrap script yang menginstall semuanya di mesin baru secara otomatis.
Bayangkan dotfiles sebagai kode infrastructure untuk workstation kalian. Seperti halnya Terraform yang menulis infrastruktur sebagai kode agar bisa direview, di-rollback, dan direproduksi — dotfiles kalian seharusnya juga:
Ada dua pendekatan utama untuk mengelola dotfiles dengan Git. Keduanya valid — pilih yang paling cocok dengan gaya kerja kalian.
git init --bare)Ide dasarnya: buat satu repository Git "telanjang" (tanpa working tree) yang menggunakan $HOME sebagai working tree. Dengan cara ini, ~/.config/nvim/ bisa di-tracking tanpa harus memindahkan file-file-nya — mereka tetap di lokasi aslinya, dan Git hanya mencatatnya.
git init --bare $HOME/.dotfiles
alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dotfiles config status.showUntrackedFiles no
dotfiles config core.excludesFile '~/.gitignore_global'
# Mulai tracking config Neovim
dotfiles add ~/.config/nvim
dotfiles commit -m "feat: add neovim config"Important
Perhatikan baris dotfiles config status.showUntrackedFiles no. Tanpa baris ini, dotfiles status akan mencoba menampilkan seluruh isi $HOME sebagai file untracked — itu sangat berisik dan berbahaya, karena $HOME berisi segalanya. Selalu set opsi ini sebelum repo dipakai.
Supaya alias dotfiles tidak hilang setiap ganti shell, simpan di file rc kalian (~/.zshrc, ~/.bashrc, atau ~/.config/fish/config.fish):
alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME'Keunggulan pendekatan ini: file-file dotfiles tetap di lokasi aslinya — tidak ada symlink yang bisa putus, dan semua aplikasi membaca config dari path standar. Ini pendekatan yang dipakai banyak engineer karena paling dekat dengan "bagaimana Git bekerja" — hanya saja working tree-nya $HOME.
Pendekatan kedua: simpan seluruh dotfiles di satu direktori (misalnya ~/dotfiles/), lalu buat symlink ke lokasi-lokasi yang dibutuhkan.
mkdir -p ~/dotfiles
git clone git@github.com:username/dotfiles.git ~/dotfiles
# Simetaskan config Neovim
ln -sf ~/dotfiles/nvim ~/.config/nvimStruktur direktori ~/dotfiles/ bisa terlihat seperti ini:
dotfiles/
├── nvim/
│ ├── init.lua
│ └── lua/
├── zsh/.zshrc
├── git/.gitconfig
├── tmux/.tmux.conf
├── install.sh
└── README.mdKeunggulannya: semua dotfiles terkumpul rapi dalam satu direktori sehingga mudah di-eksplorasi, di-backup, dan di-clone. Kekurangannya: symlink bisa putus jika struktur direktori berubah, dan kalian harus ingat membuat symlink baru setiap menambah satu dotfile baru.
Satu pertanyaan yang sering muncul: dotfiles itu publik atau privat? Jawaban jujurnya: tergantung isinya. Config Neovim pada umumnya aman untuk publik — justru banyak engineer terkenal yang mempublikasikan dotfiles-nya sebagai referensi belajar. Tapi ada beberapa hal yang tidak boleh pernah masuk ke repository publik:
~/.config/gh/hosts.yml, kredensial cloud)..env yang berisi secret.~/.zsh_history).Warning
Pola aman yang umum: satu repository publik untuk config yang ingin dibagikan, dan satu repository privat untuk yang sensitif — atau gunakan satu repository privat dan .env.local yang di-gitignore untuk secret. Di Neovim, pola ini direpresentasikan oleh file seperti .env.local yang di-load hanya jika ada, dan ditambahkan ke .gitignore. Jangan pernah menaruh secret langsung di init.lua.
Contoh: config Neovim yang membutuhkan token AI (misalnya untuk Copilot atau provider LLM). Jangan tulis tokennya langsung — baca dari environment variable atau file yang di-ignore:
-- Token dibaca dari environment, tidak pernah di-commit
local api_key = vim.env.CODIUM_API_KEY
if not api_key then
-- fallback: file .env.local yang di-gitignore
local env_file = vim.fn.stdpath("config") .. "/.env.local"
if vim.fn.filereadable(env_file) == 1 then
for line in io.lines(env_file) do
local k, v = line:match("^([^=]+)=(.*)$")
vim.env[k] = v
end
end
endDan pastikan di .gitignore:
.env.local
.env
*.token
secrets/Config yang hanya jalan di Linux adalah bom waktu. Banyak engineer bekerja di mesin kantor (Windows/Linux), laptop pribadi (macOS), dan server produksi (Linux) — dengan satu config yang sama. Kuncinya adalah mendeteksi OS secara dinamis, bukan meng-hardcode path.
Ada dua API yang paling umum dipakai: vim.loop.os_uname().sysname (nilai: Linux, Darwin, Windows_NT) dan jit.os (nilai: Linux, OSX, Windows). Kita bisa membuat module kecil yang menjadi "single source of truth" untuk deteksi OS:
local M = {}
local sysname = vim.loop.os_uname().sysname
M.is_windows = sysname == "Windows_NT"
M.is_mac = sysname == "Darwin"
M.is_linux = sysname == "Linux"
-- stdpath sudah menangani perbedaan lokasi config/data antar OS
M.config_dir = vim.fn.stdpath("config")
M.data_dir = vim.fn.stdpath("data")
M.state_dir = vim.fn.stdpath("state")
-- Lokasi yang sama antar OS tapi disimpan agar mudah di-override
M.undo_dir = M.data_dir .. "/undo"
M.session_dir = M.data_dir .. "/sessions"
M.autoload_dir = M.data_dir .. "/autoload"
return MNote
vim.fn.stdpath("config") dan vim.fn.stdpath("data") adalah kunci portabilitas di Neovim. Di Linux keduanya adalah ~/.config/nvim/ dan ~/.local/share/nvim/, di macOS sama dengan Linux, dan di Windows otomatis mengarah ke %LOCALAPPDATA%\nvim\ dan %LOCALAPPDATA%\nvim-data\. Dengan memakai API ini, kalian tidak perlu menulis path absolut yang berbeda-beda per OS.
init.luaSetelah module env.lua siap, gunakan di seluruh config untuk percabangan perilaku. Ada tiga level tempat conditional ini biasa dipakai:
undodir dan session yang perlu dibuat dulu (mkdir -p) karena di Windows lokasinya berbeda.local env = require("config.env")
vim.opt.undofile = true
vim.opt.undodir = env.undo_dir
vim.opt.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal,localoptions"
-- Pastikan direktori undo & sessions ada di semua OS
for _, dir in ipairs({ env.undo_dir, env.session_dir }) do
vim.fn.mkdir(dir, "p")
end
-- Clipboard: Windows & macOS butuh perlakuan khusus
if env.is_windows then
vim.opt.clipboard = "" -- gunakan win32yank/win32yank.exe via plugin
else
vim.opt.clipboard = "unnamedplus"
endContoh keymap yang berbeda per OS — di macOS, Ctrl banyak dipakai sistem, sehingga sebagian orang menukar leader:
local env = require("config.env")
-- Di macOS, banyak yang memakai Leader = "," atau tetap " " (spasi)
if env.is_mac then
vim.g.mapleader = ","
else
vim.g.mapleader = " "
endTerakhir, contoh conditional pada spec plugin — ada plugin yang butuh binary eksternal dengan nama berbeda per OS (misalnya rg.exe vs rg), atau build command yang berbeda:
local env = require("config.env")
{
"nvim-telescope/telescope.nvim",
dependencies = {
-- fzf-native adalah C-extension; build-nya sama di semua OS, tapi
-- membutuhkan toolchain C. Di Windows, pastikan ada `make` (e.g. via MSYS2)
{ "nvim-telescope/telescope-fzf-native.nvim", build = "make" },
},
keys = {
{ "<leader>ff", "<cmd>Telescope find_files<CR>", desc = "Find Files" },
{ "<leader>fg", "<cmd>Telescope live_grep<CR>", desc = "Live Grep" },
},
config = function()
-- rg (ripgrep) wajib ada di semua OS; path-nya dipegang Telescope sendiri
require("telescope").setup({
defaults = {
file_ignore_patterns = { "node_modules", ".git", "dist", "build" },
},
})
end,
}Tip
Prinsip DRY (Don't Repeat Yourself) juga berlaku di dotfiles: semua path dan flag yang sensitif terhadap OS dipusatkan di satu module env.lua, lalu module-module lain tinggal require. Jika nanti kalian pindah ke Windows, cukup perbaiki satu file, bukan sepuluh.
Setelah dotfiles ada di Git, langkah terakhir adalah bootstrap script: satu perintah yang menginstall Neovim beserta semua dependency-nya di mesin baru. Ini adalah script yang kalian jalankan pertama kali setelah clone. Prinsipnya sama seperti provisioning server: idempotent, cepat, dan aman dijalankan berulang.
#!/usr/bin/env bash
set -euo pipefail
# 1. Deteksi OS & pilih package manager
if [[ "$OSTYPE" == "darwin"* ]]; then
install_cmd="brew install"
deps=(neovim git ripgrep fd lazygit)
elif [[ -f /etc/debian_version ]]; then
sudo apt-get update -y
sudo apt-get install -y neovim git ripgrep fd-find
install_cmd="sudo apt-get install -y"
deps=()
elif [[ "$OSTYPE" == "msys" ]] || grep -qi microsoft /proc/version 2>/dev/null; then
echo "Gunakan winget/scoop di Windows, atau jalankan ini di WSL." >&2
exit 1
fi
for pkg in "${deps[@]}"; do
$install_cmd "$pkg"
done
# 2. Setup bare repo dotfiles (sesuaikan dengan remote kalian)
git clone --bare https://github.com/username/dotfiles.git "$HOME/.dotfiles"
alias dotfiles='/usr/bin/git --git-dir=$HOME/.dotfiles --work-tree=$HOME'
dotfiles config status.showUntrackedFiles no
dotfiles checkout
dotfiles submodule update --init --recursive
# 3. Install plugin Neovim secara headless (tanpa UI)
nvim --headless "+Lazy! sync" +qa
nvim --headless "+MasonInstallAll" +qa 2>/dev/null || true
# 4. Verifikasi
nvim --headless -c 'lua print("dotfiles ready ✔")' -c 'qa'
echo "Setup selesai. Buka Neovim dan nikmati config kalian!"curl -fsSL https://raw.githubusercontent.com/username/dotfiles/main/install.sh | bashBanyak yang menyebut pola ini "provisioning as code untuk workstation". Anggap saja seperti terraform apply untuk laptop kalian — satu sumber kebenaran, satu perintah, hasil yang dapat diprediksi. Ketika kalian berganti laptop atau menambahkan server baru, tidak ada lagi pertanyaan "plugin apa yang harus saya install?"
Caution
Peringatan keamanan: menjalankan curl | bash dari internet adalah praktik yang rawan jika tidak hati-hati. Pastikan kalian meninjau isi script sebelum menjalankannya (atau setidaknya memastikan repository milik kalian sendiri dan branch yang benar). Untuk environment perusahaan, lebih aman men-download script, review, lalu eksekusi secara terpisah.
Secret bocor ke repository. Paling berbahaya dan paling sering terjadi. Solusi: gunakan .gitignore, baca secret dari environment atau file .env.local, dan sebelum push pertama, periksa dotfiles status dengan teliti. Kalau terlanjur bocor, rotasi secret itu segera — Git history tidak akan memaafkan.
Hardcode path absolut. Menulis /home/arman/.local/share/nvim/... akan rusak di mesin lain. Gunakan vim.fn.stdpath(), vim.fn.expand("~"), atau module env.lua.
Plugin path berbeda per OS. Beberapa plugin memerlukan binary eksternal yang lokasinya berbeda (misalnya fd vs fdfind di Debian, atau make yang tidak ada secara default di Windows). Deteksi OS dan dokumentasikan dependency di install.sh.
init.lua yang menolak jalan di Windows. Perhatikan perbedaan: path separator (\ vs /), shell default (pwsh vs bash), dan vim.opt.clipboard yang perlu plugin tambahan (win32yank). Satu kondisi if env.is_windows di awal config akan menyelamatkan banyak debugging.
Symlink yang putus. Jika memakai pendekatan symlink dan kemudian merestrukturisasi ~/dotfiles/, semua symlink yang menunjuk ke path lama akan patah. Gunakan satu lokasi yang stabil, dan verifikasi dengan ls -l setelah setup.
Lupa meng-commit perubahan. Dotfiles hanya berguna jika selalu sinkron. Jadikan kebiasaan: setelah menyetel config sampai nyaman, langsung dotfiles add -A && dotfiles commit. Semakin sering commit, semakin aman.
Sebelum menganggap config kalian "siap lintas mesin", lewati checklist ini:
| No | Item | Status |
|---|---|---|
| 1 | Config tersimpan di repository Git (bare atau symlink) | ☐ |
| 2 | Tidak ada secret/token di repository | ☐ |
| 3 | Semua path memakai stdpath / $HOME / module env.lua | ☐ |
| 4 | Deteksi OS (Linux/macOS/Windows) terpusat di satu module | ☐ |
| 5 | Directory undodir, session dibuat otomatis (mkdir -p) | ☐ |
| 6 | Bootstrap script idempotent & sudah teruji di 2+ mesin | ☐ |
| 7 | Dependency eksternal terdokumentasi di install.sh / README | ☐ |
Pada episode 24 ini kita telah belajar bahwa config Neovim kalian adalah aset yang harus dikelola secara profesional: menyimpannya ke Git melalui pendekatan bare repository atau symlink, memisahkan yang privat dari yang publik, membuatnya portabel lintas platform dengan module env.lua dan vim.fn.stdpath(), serta mengotomatiskan seluruh setup dengan bootstrap script. Mulai sekarang, pindah ke mesin baru bukan lagi mimpi buruk — cukup clone, bootstrap, dan selesai.
Poin kuncinya: dotfiles adalah investasi. Waktu yang kalian habiskan untuk merapikannya hari ini akan dibayar kembali berkali-kali lipat setiap kali kalian berpindah mesin, dan sekaligus menjadi portofolio yang menunjukkan bagaimana kalian bekerja sebagai engineer.
Di episode 25 selanjutnya, kita akan membahas pertanyaan yang sering menghantui setiap pengguna Neovim: haruskah saya membangun config sendiri dari nol, atau cukup memakai distro seperti LazyVim, NvChad, atau AstroNvim? Kita akan membandingkan kelebihan dan kekurangan masing-masing, kapan harus memilih yang mana, dan bagaimana menjadikan Neovim sebagai daily driver yang sesungguhnya. Sampai jumpa!