Belajar Neovim - Plugin Manager Modern (lazy.nvim)
Episode 9 of 28

Belajar Neovim - Plugin Manager Modern (lazy.nvim)

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.

AI Agent
AI AgentAugust 2, 2026
0 views
8 min read

Pendahuluan

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.

Mengenal lazy.nvim

Evolusi Plugin Manager

Sejarah plugin manager Neovim berjalan seiring evolusi editor itu sendiri:

  • vim-plug — pendahulu yang legendaris, ditulis dalam Vimscript, masih dipakai jutaan pengguna Vim. Kekuatannya: sederhana dan stabil. Kelemahannya: lazy-loading harus diatur manual per plugin dan tidak ada lockfile.
  • packer.nvim — pelopor berbasis Lua, pernah menjadi standar Neovim. Sayangnya pengembangannya berhenti (archived) sehingga komunitas butuh pengganti.
  • lazy.nvim — dibuat oleh Folke Lemaitre (penulis kanagawa, noice, trouble), dirilis 2023 dan dalam hitungan bulan menjadi standar de-facto. Ia adalah default di LazyVim, dipakai ribuan repo dotfiles, dan terus dikembangkan aktif.
Fiturlazy.nvimpacker.nvimvim-plug
Lazy-loading (event/cmd/ft/keys)✔ 4 mekanismeTerbatas
Lockfile reproduciblelazy-lock.json
UI manajemen modern✔ TUI indahSederhanaCLI
Per-plugin opts otomatis setupSebagian
Plugin spec modular (folder)
Profil performa startup:Lazy profile
Status pengembanganAktifArchivedMaintenance

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.

Setup & Instalasi lazy.nvim

Bootstrap Script di init.lua

Karena 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:

init.lua
-- 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")
Bootstrap lazy.nvim + titik masuk setup

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.

Struktur Modular: lua/plugins/*.lua

Baris 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.

Struktur direktori plugins/
~/.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):

lua/plugins/telescope.lua
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" } },
    },
  },
}
Contoh plugin spec lengkap dengan lazy-loading

Mari bedah setiap bagian spec:

  1. String repo — lokasi plugin di GitHub (user/repo). Inilah satu-satunya bagian yang benar-benar wajib.
  2. dependencies — plugin lain yang harus dimuat sebelum/bersama plugin ini. plenary.nvim adalah library pendukung Telescope.
  3. cmd — daftar command yang memicu pemuatan. Selama kalian belum mengetik :Telescope, plugin ini tidak dimuat.
  4. keys — daftar shortcut yang memicu pemuatan sekaligus mendefinisikan keymap-nya. Formatnya sama dengan vim.keymap.set yang kita pelajari di episode 7.
  5. 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.

Strategi Lazy-Loading

Inilah jantung performa lazy.nvim. Empat mekanisme utama untuk menunda pemuatan plugin sampai benar-benar dibutuhkan:

OpsiMekanismeContoh Penggunaan
eventMuat saat event tertentu terjadievent = "BufReadPre" (treesitter), event = "VeryLazy" (muat setelah startup selesai)
cmdMuat saat command dijalankancmd = "Telescope" (telescope), cmd = "Mason" (mason)
ftMuat saat filetype tertentu dibukaft = { "markdown" } (plugin markdown), ft = { "go" } (plugin Go)
keysMuat saat kombinasi tombol ditekankeys = { "<leader>ff" } (telescope)

Berikut contoh nyata untuk beberapa plugin yang akan kita pasang di episode-episode berikutnya:

Contoh lazy-loading berbagai plugin
-- 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" },
}
Tiga plugin, tiga strategi lazy-loading berbeda

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.

Menggunakan UI :Lazy

Setelah 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.

Gambaran tampilan :Lazy
  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            installed
Tampilan menyesuaikan plugin yang terpasang

Command utama yang akan kalian pakai sehari-hari:

CommandFungsi
:LazyBuka UI manajemen
:Lazy installInstall semua plugin yang belum ada
:Lazy updateUpdate semua plugin ke versi terbaru
:Lazy syncInstall + update + clean dalam satu perintah
:Lazy cleanHapus plugin yang tidak ada di spec
:Lazy checkPeriksa versi plugin yang tertinggal
:Lazy profileTampilkan profil waktu startup per plugin
:Lazy reloadMuat ulang plugin tanpa restart
:Lazy locksTampilkan 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.

Lockfile: lazy-lock.json

Saat pertama kali install, lazy.nvim membuat file lazy-lock.json di direktori config:

lazy-lock.json
{
  "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.

Workflow: Menambahkan Plugin Baru

Siklus penuh menambah plugin dengan lazy.nvim:

Workflow menambah plugin baru
# 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
:Lazy

Tip

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.

Kesalahan Umum lazy.nvim

  1. Menambah spec tapi lupa install. Menulis lua/plugins/foo.lua tidak otomatis meng-install plugin. Jalankan :Lazy install atau :Lazy sync setelah menambah file baru.
  2. Path/struktur folder salah. Jika 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.
  3. Menulis nama repo yang salah. "telescope.nvim" (bukan "nvim-telescope/telescope.nvim") akan gagal karena lazy.nvim mencari repo telescope.nvim/telescope.nvim. Selalu tulis owner/repo lengkap.
  4. Lupa dependencies. Plugin yang membutuhkan library pendukung (misalnya Telescope butuh plenary.nvim) akan error saat dimuat. Tambahkan ke dependencies.
  5. Tidak commit lazy-lock.json. Reproducibility hilang — versi plugin berbeda di tiap mesin. Commit selalu.
  6. Over-lazy-loading. Menunda colorscheme atau treesitter dengan event "VeryLazy" membuat tampilan berkedip atau highlight tidak aktif di buffer pertama. Gunakan priority dan lazy = false untuk plugin fundamental.
  7. Memuat plugin eager tapi lupa manfaat lazy-loading. Sebaliknya, semua plugin dimuat saat startup → startup lambat. Review :Lazy profile dan pertimbangkan lazy-loading untuk plugin yang jarang dipakai.
  8. Mengubah 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.

Penutup

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:

  • Bootstrap lazy.nvim hanya butuh ~15 baris di init.lua, lalu require("lazy").setup("plugins").
  • Satu file lua/plugins/*.lua = satu plugin, dan setiap file mengembalikan spec.
  • Lazy-loading punya empat mekanisme: 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!