Tutup FASE 2 dengan fondasi ekosistem: pelajari mengapa lazy.nvim menjadi standar de-facto plugin manager, tulis bootstrap script di init.lua, susun plugin spec modular di lua/plugins/, dan kuasai UI :Lazy untuk install, update, clean, hingga profil performa.

Setelah di episode 8 sebelumnya kita membangun autocommand, custom commands, dan filetype detection — kalian sekarang mampu membuat Neovim bekerja secara reaktif dan kontekstual. Tapi mari kita jujur sejenak: ada satu hal yang belum bisa dilakukan dengan murni config manual, yaitu menambahkan fitur yang belum ada di Neovim core. Fuzzy finder ala VS Code, syntax highlighting berbasis Treesitter, integrasi LSP penuh, statusline yang indah — semuanya butuh plugin.
Dan di dunia Neovim modern, plugin tidak pernah di-install manual dengan git clone. Ada manajernya — dan di episode kali ini, kita akan membangun fondasi yang akan menemani seluruh sisa series: lazy.nvim.
Mengapa topik ini menutup FASE 2 (Windows, Buffers & Lua Configuration) dengan sempurna? Karena lazy.nvim adalah bukti nyata dari semua yang kita pelajari: ia ditulis dalam Lua, dikonfigurasi dengan tabel Lua, dimuat melalui modul require, dan memanfaatkan event autocommand untuk lazy-loading. Jika kalian sudah memahami empat episode sebelumnya, maka episode ini terasa seperti reuni — semua konsep bertemu di satu tempat.
Bagi kalian yang berkarir sebagai DevOps/SRE, pemahaman ini juga berharga secara langsung: prinsip lockfile (lazy-lock.json), reproducible install, dan dependency management di lazy.nvim adalah konsep yang sama dengan yang kalian kelola di package.json, go.mod, requirements.txt, atau lockfile di pipeline CI.
lazy.nvimSejarah plugin manager Neovim berjalan seiring evolusi editor itu sendiri:
| Fitur | lazy.nvim | packer.nvim | vim-plug |
|---|---|---|---|
| Lazy-loading (event/cmd/ft/keys) | ✔ 4 mekanisme | ✔ | Terbatas |
| Lockfile reproducible | ✔ lazy-lock.json | ✔ | ✘ |
| UI manajemen modern | ✔ TUI indah | Sederhana | CLI |
Per-plugin opts otomatis setup | ✔ | Sebagian | ✘ |
| Plugin spec modular (folder) | ✔ | ✔ | ✘ |
| Profil performa startup | ✔ :Lazy profile | ✘ | ✘ |
| Status pengembangan | Aktif | Archived | Maintenance |
Note
Mengapa lazy.nvim menang telak? Karena ia memecahkan masalah yang paling mengganggu pengguna Neovim: startup time. Config dengan 50+ plugin yang semuanya dimuat saat startup bisa memakan 500ms–1s hanya untuk membuka Neovim. Dengan lazy-loading, setiap plugin dimuat hanya saat benar-benar dibutuhkan — hasilnya Neovim bisa buka di bawah 50ms meskipun memiliki 100 plugin. Inilah yang membuatnya bukan sekadar manager, melainkan pengubah paradigma.
lazy.nviminit.luaKarena lazy.nvim sendiri adalah plugin, ia harus di-install terlebih dahulu — dan caranya yang paling elegan adalah bootstrap otomatis: script kecil di init.lua yang meng-clone lazy.nvim ke direktori data Neovim jika belum ada. Beginilah caranya:
-- 1. Tentukan path lazy.nvim di direktori data Neovim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
-- 2. Clone jika belum ada
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
-- 3. Tambahkan lazy.nvim ke runtimepath
vim.opt.rtp:prepend(lazypath)
-- 4. Mulai lazy.nvim dan muat semua spec di folder lua/plugins/
require("lazy").setup("plugins")Tip
Dua detail teknis penting dari script di atas. Pertama, vim.fn.stdpath("data") mengembalikan lokasi penyimpanan data Neovim (biasanya ~/.local/share/nvim/) — inilah tempat yang tepat untuk plugin, terpisah dari direktori config. Kedua, vim.uv.fs_stat mengecek keberadaan folder; vim.uv adalah API baru (Neovim 0.10+), sedangkan vim.loop adalah nama lamanya — menulis (vim.uv or vim.loop) membuat script kompatibel lintas versi. Terakhir, --filter=blob:none membuat clone jauh lebih cepat karena hanya mengambil metadata Git.
lua/plugins/*.luaBaris paling penting adalah require("lazy").setup("plugins"). Ketika argumen yang diberikan adalah sebuah direktori ("plugins"), lazy.nvim secara otomatis memuat semua file .lua di dalam lua/plugins/ — dan setiap file mengembalikan satu atau lebih plugin spec.
~/.config/nvim/
├── init.lua
└── lua/
├── config/
│ ├── options.lua
│ ├── keymaps.lua
│ ├── autocmds.lua
│ └── lazy.lua
└── plugins/
├── telescope.lua # satu file = satu plugin
├── treesitter.lua
├── lsp.lua
├── cmp.lua
└── ...Note
Pola "satu file per plugin" bukan aturan keras, melainkan konvensi yang membuat config kalian mudah dibaca dan di-maintain. Saat sebuah plugin bermasalah, kalian tahu persis file mana yang harus dibuka. Saat ingin menonaktifkan plugin, cukup komentari return-nya atau set { enabled = false } di dalam spec. Persis seperti memecah service menjadi microservice — modular, isolasi, dan jelas tanggung jawabnya.
Setiap file di lua/plugins/ mengembalikan sebuah spec — tabel Lua yang menjelaskan plugin mana yang di-install, dari mana, kapan dimuat, dan bagaimana dikonfigurasi. Berikut contoh spec lengkap untuk telescope.nvim (fuzzy finder yang akan kita bahas detail di episode 11):
return {
-- 1. Sumber plugin (nama repo GitHub)
"nvim-telescope/telescope.nvim",
tag = "0.1.8", -- ikat versi stabil tertentu
-- 2. Dependensi: dimuat bersama plugin ini
dependencies = { "nvim-lua/plenary.nvim" },
-- 3. Lazy-loading: muat saat command :Telescope dipanggil
cmd = "Telescope",
-- 4. Lazy-loading: muat saat tombol berikut ditekan
keys = {
{ "<leader>ff", "<cmd>Telescope find_files<CR>", desc = "Cari file" },
{ "<leader>fg", "<cmd>Telescope live_grep<CR>", desc = "Cari teks (grep)" },
{ "<leader>fb", "<cmd>Telescope buffers<CR>", desc = "Daftar buffer" },
},
-- 5. Konfigurasi: tabel ini diteruskan ke fungsi setup() plugin
opts = {
defaults = {
prompt_prefix = " ",
sorting_strategy = "ascending",
layout_config = { horizontal = { prompt_position = "top" } },
},
},
}Mari bedah setiap bagian spec:
user/repo). Inilah satu-satunya bagian yang benar-benar wajib.dependencies — plugin lain yang harus dimuat sebelum/bersama plugin ini. plenary.nvim adalah library pendukung Telescope.cmd — daftar command yang memicu pemuatan. Selama kalian belum mengetik :Telescope, plugin ini tidak dimuat.keys — daftar shortcut yang memicu pemuatan sekaligus mendefinisikan keymap-nya. Formatnya sama dengan vim.keymap.set yang kita pelajari di episode 7.opts — tabel konfigurasi yang otomatis diteruskan ke require("telescope").setup(opts). Pola ini menghilangkan boilerplate manual.Tip
Perhatikan bahwa keys dan opts saling melengkapi dengan sempurna. Keymap yang kalian definisikan di keys akan aktif bersamaan dengan pemuatan plugin (bukan menunggu plugin dimuat, berkat mekanisme "lazy keys" milik lazy.nvim). Sementara opts menyatu dengan setup plugin. Dengan dua fitur ini, kalian tidak perlu menulis keymap terpisah di keymaps.lua untuk plugin — semua hidup dalam satu spec.
Inilah jantung performa lazy.nvim. Empat mekanisme utama untuk menunda pemuatan plugin sampai benar-benar dibutuhkan:
| Opsi | Mekanisme | Contoh Penggunaan |
|---|---|---|
event | Muat saat event tertentu terjadi | event = "BufReadPre" (treesitter), event = "VeryLazy" (muat setelah startup selesai) |
cmd | Muat saat command dijalankan | cmd = "Telescope" (telescope), cmd = "Mason" (mason) |
ft | Muat saat filetype tertentu dibuka | ft = { "markdown" } (plugin markdown), ft = { "go" } (plugin Go) |
keys | Muat saat kombinasi tombol ditekan | keys = { "<leader>ff" } (telescope) |
Berikut contoh nyata untuk beberapa plugin yang akan kita pasang di episode-episode berikutnya:
-- Plugin Tree-sitter: dimuat saat buffer dibaca
return {
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
event = { "BufReadPre", "BufNewFile" },
main = "nvim-treesitter.configs",
opts = { highlight = { enable = true } },
}
-- Plugin Mason (LSP installer): dimuat saat :Mason dipanggil
return {
"williamboman/mason.nvim",
cmd = "Mason",
opts = {},
}
-- Colorscheme: dimuat paling awal dengan priority tinggi
return {
"catppuccin/nvim",
name = "catppuccin",
priority = 1000, -- dimuat sebelum plugin lain
lazy = false, -- muat di startup (bukan lazy)
opts = { flavour = "mocha" },
}Important
Tidak semua plugin harus di-lazy-load. Plugin yang menentukan tampilan awal (colorscheme, statusline) dan plugin yang berperan sebagai "otot" di setiap buffer (treesitter, compiler) justru harus dimuat lebih awal. Untuk colorscheme, gunakan priority = 1000 dan lazy = false agar warnanya tidak "berkedip" saat startup. Aturan praktisnya: muat segera apa yang dibutuhkan sejak detik pertama, tunda sisanya. Jangan menunda segalanya hanya demi angka startup — ukurlah manfaat nyatanya.
:LazySetelah setup selesai, buka Neovim dan ketik :Lazy. Kalian akan melihat TUI yang cantik: daftar semua plugin dengan status install-nya, kotak pencarian, dan tombol aksi di bawah.
Lazy.nvim
A plugin manager for Neovim
⚡ Install all missing plugins
⬆ Update plugins
🗑 Clean unused plugins
⏱ Profile startup time
Plugins:
telescope.nvim installed v0.1.8
plenary.nvim installed v2.0.0
nvim-treesitter installed
catppuccin installedCommand utama yang akan kalian pakai sehari-hari:
| Command | Fungsi |
|---|---|
:Lazy | Buka UI manajemen |
:Lazy install | Install semua plugin yang belum ada |
:Lazy update | Update semua plugin ke versi terbaru |
:Lazy sync | Install + update + clean dalam satu perintah |
:Lazy clean | Hapus plugin yang tidak ada di spec |
:Lazy check | Periksa versi plugin yang tertinggal |
:Lazy profile | Tampilkan profil waktu startup per plugin |
:Lazy reload | Muat ulang plugin tanpa restart |
:Lazy locks | Tampilkan isi lockfile |
Di dalam UI :Lazy, navigasi juga mudah: I untuk install, U untuk update, C untuk clean, p untuk profile, dan Enter untuk melihat detail plugin. Shortcut di atas layar TUI selalu menampilkan tombol yang tersedia.
lazy-lock.jsonSaat pertama kali install, lazy.nvim membuat file lazy-lock.json di direktori config:
{
"telescope.nvim": { "commit": "3b8a7f2..." },
"plenary.nvim": { "commit": "d6c8a3e..." },
"nvim-treesitter": { "commit": "f2e4b1a..." }
}Warning
Commit file lazy-lock.json ke repository dotfiles kalian. Lockfile adalah kontrak versi: ia mengunci commit setiap plugin sehingga install di mesin lain (atau di CI) menghasilkan versi yang identik dengan mesin kalian. Tanpa lockfile, dua orang di tim yang sama bisa memiliki versi plugin berbeda — dan perbedaan itulah sumber bug yang paling licik ("kok error di saya tapi tidak di dia?"). Prinsip ini identik dengan package-lock.json atau bun.lock yang kalian kelola di project — kalian sudah familiar.
Siklus penuh menambah plugin dengan lazy.nvim:
# 1. Buat spec file baru di lua/plugins/
# contoh: lua/plugins/telescope.lua
# 2. Restart Neovim (atau :Lazy reload)
nvim
# 3. Install plugin yang baru ditambahkan
:Lazy install
# 4. Periksa apakah semuanya bersih
:LazyTip
Setelah mengubah spec, jangan selalu restart manual. :Lazy reload plugins akan memuat ulang semua plugin spec tanpa menutup editor. Dan jika kalian menambah plugin baru, :Lazy sync adalah satu perintah yang melakukan install sekaligus update dan clean — cukup untuk kebanyakan kasus.
lazy.nvimlua/plugins/foo.lua tidak otomatis meng-install plugin. Jalankan :Lazy install atau :Lazy sync setelah menambah file baru.require("lazy").setup("plugins") tidak menemukan folder, lazy.nvim akan diam tanpa meng-install apa pun (atau error "module not found"). Pastikan folder benar-benar bernama lua/plugins/ relatif terhadap init.lua."telescope.nvim" (bukan "nvim-telescope/telescope.nvim") akan gagal karena lazy.nvim mencari repo telescope.nvim/telescope.nvim. Selalu tulis owner/repo lengkap.dependencies. Plugin yang membutuhkan library pendukung (misalnya Telescope butuh plenary.nvim) akan error saat dimuat. Tambahkan ke dependencies.lazy-lock.json. Reproducibility hilang — versi plugin berbeda di tiap mesin. Commit selalu.priority dan lazy = false untuk plugin fundamental.:Lazy profile dan pertimbangkan lazy-loading untuk plugin yang jarang dipakai.opts tapi tidak melihat efeknya. opts hanya diterapkan saat setup plugin. Pastikan format tabelnya benar dan restart / :Lazy reload setelah mengubah.Note
Diagnosa masalah dengan cepat: error saat startup biasanya muncul sebagai teks merah dengan nama plugin yang bermasalah. Periksa :Lazy profile untuk melihat plugin mana yang lambat, dan :Lazy untuk melihat status install. Jika sebuah plugin gagal total, komentari spec-nya (atau set { enabled = false }) lalu :Lazy sync untuk melanjutkan — config tidak perlu lumpuh karena satu plugin rusak.
Di episode 9 ini kita telah menutup FASE 2 dengan membangun fondasi ekosistem yang akan dipakai di seluruh sisa series. Kalian memahami mengapa lazy.nvim menjadi standar de-facto — lazy-loading berbasis event, lockfile untuk stabilitas, dan UI manajemen yang indah. Kalian menulis bootstrap script di init.lua yang meng-clone dan memuat lazy.nvim secara otomatis. Kalian menyusun plugin spec modular di lua/plugins/*.lua dengan dependencies, cmd, keys, dan opts. Terakhir, kalian menguasai UI :Lazy untuk install, update, clean, sync, hingga profile.
Poin penting yang harus kalian bawa:
init.lua, lalu require("lazy").setup("plugins").lua/plugins/*.lua = satu plugin, dan setiap file mengembalikan spec.event, cmd, ft, keys — pilih sesuai kapan plugin dibutuhkan.lazy-lock.json wajib di-commit untuk stabilitas lintas mesin.:Lazy sync adalah satu perintah untuk install + update + clean.Ini adalah episode terakhir dari FASE 2. Dari sini, kalian telah membangun Neovim yang nyaman (options & keymaps), reaktif (autocommand & custom commands), dan siap menerima plugin (lazy.nvim). Di FASE 3, kalian mulai mempercantik editor: di episode 10 kita akan membahas Kustomisasi Visual, Colorscheme & Statusline — meng-install theme modern seperti Tokyo Night atau Catppuccin, membangun statusline informatif dengan lualine.nvim, dan menambahkan bufferline serta indent guides. Bayangkan hasilnya: Neovim kalian akan tampil seindah IDE komersial, tanpa beban startup yang berat. Pastikan tetap semangat!