이 글은 Neovim 시리즈의 다섯 번째 글입니다.
- Neovim 입문: Vim을 넘어서는 첫걸음
- Neovim 중급: 생산성을 높이는 기능들
- Neovim 고급: 플러그인과 LSP로 IDE처럼 쓰기
- 나의 Neovim 설정 전체 공개
- LazyVim distro로 갈아타기 ← 현재 글
함께 읽기: LazyVim 키맵 치트시트
들어가며
플러그인 23개를 직접 큐레이션해서 1년 가까이 굴렸지만, 결국 LazyVim distro로 갈아탔어요. 플러그인 수는 23개에서 42개로 늘었지만 제가 직접 관리해야 하는 파일은 15개에서 5개로 줄었고, 이 비대칭이 distro의 핵심이에요.
직전 셋업 공개 글에서 정리했던 lazy.nvim 수동 구성은 잘 동작했습니다. 다만 새 언어 LSP 하나를 붙일 때마다 mason 설정, conform 포매터, nvim-cmp 소스를 손으로 동기화해야 했고, 새 머신에 그대로 옮길 때마다 의존성이 한두 개씩 빠졌습니다. distro는 그 동기화를 일괄로 위임하고, 제 영역은 “취향 차이가 나는 부분"에만 남기는 구조입니다.
이 글은 LazyVim이라는 distro가 무엇이고, 수동 셋업에서 어떤 흐름으로 옮겼고, 어디에 백업을 두고 어떻게 롤백할 수 있는지를 정리합니다.
distro란 무엇인가
Neovim distro는 lazy.nvim, LSP, treesitter, 자동완성, UI 같은 표준 기반을 한 묶음으로 깔아주고, 사용자는 그 위에 얇게 커스텀만 얹는 셋업 패턴입니다. 직접 lua 파일을 한 줄 한 줄 짜는 대신, 프레임워크가 정해 둔 슬롯에 옵션이나 추가 spec만 끼워 넣으면 됩니다.
| distro | 분위기 |
|---|---|
| LazyVim | 가장 표준적/미니멀. lazy.nvim 작성자가 직접 운영. 본 글 대상 |
| LunarVim | 자체 CLI(lvim)를 가진 비교적 무거운 셋업 |
| NvChad | UI/테마 중심, 화려한 시작 화면이 특징 |
| AstroNvim | 대시보드, 아이콘, 통계 정보가 많은 풍성한 셋업 |
LazyVim을 고른 이유는 단순합니다. 이미 쓰던 lazy.nvim 위에 그대로 얹히고, 빠지더라도 ~/.config/nvim을 통째로 갈아엎지 않아도 되는 구조이기 때문입니다. distro 자체가 lazy 플러그인 하나처럼 동작합니다.
직전 상태
수동 lazy.nvim으로 플러그인 23개를 구성한 상태였습니다.
자세한 구성은 나의 Neovim 설정 전체 공개 글에 있습니다. 요약하면:
init.lua1줄 →lua/config/에서 globals/options/keymaps 분리 로드lua/plugins/아래 플러그인별 파일 15개 (telescope, neo-tree, lsp, cmp, treesitter, conform, kanagawa 등)- 자체 작성한
keyMapper유틸로noremap=true silent=true일괄 적용 - 테마는 Kanagawa Dragon (저채도 다크)
문제는 없었습니다. 단지 새 언어 추가가 매번 작은 의식이었습니다. Go를 붙이려면 mason.nvim에 gopls를 추가하고, conform.nvim에 gofmt를 등록하고, nvim-lspconfig 호출 라인을 늘리고, treesitter parser 목록도 손봐야 했습니다. 그렇게 해 둔 구성을 새 노트북에 옮기면 :checkhealth에 빨간 줄이 한두 개 떴습니다.
LazyVim이 자동으로 가져오는 것
LazyVim 15.x를 깔면 다음이 한 번에 따라옵니다.
| 영역 | 들어오는 것 |
|---|---|
| 플러그인 매니저 | lazy.nvim |
| 파일 탐색/검색 | snacks.picker, snacks.dashboard, neo-tree |
| 키 안내 | which-key |
| LSP, 포매터, 린터 | nvim-lspconfig + mason 자동 설치 |
| 자동완성 | blink.cmp (또는 nvim-cmp 옵션) |
| 구문 파싱 | nvim-treesitter |
| Git | gitsigns, lazygit 연동 |
| UI | bufferline, lualine, noice, mini.icons |
| 포매팅 | conform.nvim + format-on-save |
여기에 제가 켠 LazyExtras 6종(go, typescript, markdown, json, yaml, python)이 마저 붙습니다. 합치면 42개입니다. 직접 관리할 필요는 없고, 동작에 손대고 싶으면 같은 spec을 opts만 덮어씌우는 식으로 가볍게 끼어듭니다.
제가 짠 파일은 5개만 남았습니다. 나머지는 distro 본체가 가져간 책임입니다.
백업과 롤백 안전망
distro 전환은 비가역 작업이 아니어야 합니다. Neovim의 상태는 네 군데에 흩어져 있어서, 그걸 다 같이 빼두지 않으면 깔끔한 롤백이 어렵습니다.
기존 nvim 상태 4종을 .backup-2026-05-07 suffix로 옮긴 뒤 새 LazyVim을 깔았습니다.
| 원본 | 백업 |
|---|---|
~/.config/nvim | ~/.config/nvim.backup-2026-05-07 |
~/.local/share/nvim (164MB, 컴파일된 플러그인) | ~/.local/share/nvim.backup-2026-05-07 |
~/.local/state/nvim | ~/.local/state/nvim.backup-2026-05-07 |
~/.cache/nvim | ~/.cache/nvim.backup-2026-05-07 |
문제 생겼을 때 롤백은 4쌍을 역순으로 mv하면 됩니다. 새 LazyVim을 같은 suffix로 옮긴 뒤 백업을 원래 자리로:
DATE=2026-05-07
mv ~/.config/nvim ~/.config/nvim.lazyvim-$DATE
mv ~/.local/share/nvim ~/.local/share/nvim.lazyvim-$DATE
mv ~/.local/state/nvim ~/.local/state/nvim.lazyvim-$DATE
mv ~/.cache/nvim ~/.cache/nvim.lazyvim-$DATE
mv ~/.config/nvim.backup-$DATE ~/.config/nvim
mv ~/.local/share/nvim.backup-$DATE ~/.local/share/nvim
mv ~/.local/state/nvim.backup-$DATE ~/.local/state/nvim
mv ~/.cache/nvim.backup-$DATE ~/.cache/nvim
이 안전망이 있어야 distro 전환을 부담 없이 시도해볼 수 있습니다.
새 디렉토리 구조
~/.config/nvim/
├── init.lua # LazyVim 부트스트랩 (starter 그대로)
├── lua/
│ ├── config/
│ │ ├── options.lua # 사용자 추가: scrolloff=10
│ │ ├── keymaps.lua # 사용자 추가: <leader>h, <C-;>
│ │ ├── autocmds.lua # 사용자 추가: 마크다운 wrap/linebreak/spell=false 등
│ │ └── lazy.lua # LazyVim 부트스트랩 (수정 X)
│ └── plugins/
│ ├── colorscheme.lua # 신규: Solarized + Everforest + Gruvbox Material
│ ├── markdown.lua # 신규: render-markdown.nvim 옵션 강화
│ ├── ufo.lua # 신규: nvim-ufo (LSP 폴딩)
│ ├── floaterm.lua # 신규: vim-floaterm + <C-;>
│ ├── lang-extras.lua # 신규: LazyExtras 6종 일괄 import
│ └── example.lua # starter 동봉 예제 (`if true then return {} end`로 비활성)
├── lazyvim.json # LazyVim 자동 생성
├── lazy-lock.json # lazy.nvim이 잠금 관리
└── stylua.toml # starter 동봉 (lua 포매터 설정)
config/는 LazyVim의 starter 템플릿이 깔아준 그대로입니다. 사용자 영역은 plugins/ 아래 5개 파일과 config/의 keymaps/options/autocmds 추가분이며, 그게 전부입니다.
커스텀 5개 플러그인 파일
distro가 가져가지 않은 “제 취향"은 다섯 갈래로 정리됐습니다.
lua/plugins/colorscheme.lua
테마 후보 3종을 동시에 등록했습니다.
직전엔 Kanagawa Dragon 단일 테마였는데, 마크다운 작성 비중이 늘면서 헤딩 위계와 코드블록 배경이 더 또렷한 테마가 필요해졌습니다. 즉시 비교를 위해 셋을 같이 등록했습니다.
maxmx03/solarized.nvim(variant=winter) — 기본neanias/everforest-nvim(background=soft)sainnhe/gruvbox-material(background=medium)
런타임에 :colorscheme everforest처럼 즉시 갈아끼울 수 있고, 영구화는 LazyVim 기본 colorscheme 라인을 바꾸면 됩니다. UI에서 라이브 프리뷰로 고르고 싶으면 <Space>uC.
lua/plugins/markdown.lua
render-markdown.nvim 옵션을 강화했습니다.
LazyExtras lang.markdown이 이미 render-markdown.nvim의 spec을 등록합니다. 거기에 opts만 덮어씌워 가독성 옵션을 강화했습니다.
return {
{
"MeanderingProgrammer/render-markdown.nvim",
opts = {
heading = {
sign = false,
icons = { "◉ ", "○ ", "✸ ", "✿ ", "✤ ", "✜ " },
backgrounds = {
"RenderMarkdownH1Bg", "RenderMarkdownH2Bg",
"RenderMarkdownH3Bg", "RenderMarkdownH4Bg",
"RenderMarkdownH5Bg", "RenderMarkdownH6Bg",
},
},
code = {
style = "full",
position = "left",
width = "block",
left_pad = 2,
},
quote = { icon = "┃" },
bullet = { icons = { "●", "○", "◆", "◇" } },
checkbox = {
unchecked = { icon = " " },
checked = { icon = " " },
},
pipe_table = { style = "full", alignment_indicator = "━" },
link = { image = " ", hyperlink = " " },
},
},
}
| 옵션 | 효과 |
|---|---|
heading.icons | H1~H6 아이콘으로 위계 구분 |
heading.backgrounds | 헤딩 줄 전체 배경 틴트 (테마의 RenderMarkdownH* highlight 그룹 위임) |
code.style = "full" | 코드블록 전체 배경 + 좌측 언어 라벨 |
code.width = "block" | 코드블록 너비를 본문보다 좁게 (들여쓰기 효과) |
quote.icon | 인용문 좌측 세로바 |
bullet.icons | 리스트 깊이별 글리프 (● ○ ◆ ◇) |
checkbox | [ ]/[x]를 Nerd Font 글리프로 |
pipe_table.style = "full" | 표 경계 전체 표시 |
색상은 테마의 highlight 그룹에 위임했기 때문에 colorscheme를 바꿔도 헤딩 틴트가 자동으로 따라옵니다.
lua/plugins/ufo.lua
LSP 인지 폴딩을 설정했습니다.
nvim-ufo를 사용합니다. foldcolumn=0, foldlevel=99로 기본은 모두 펼친 상태로 두고, 필요할 때만 zc/zo로 접고 폅니다.
lua/plugins/floaterm.lua
<C-;>로 토글하도록 설정했습니다.
LazyVim 기본 <C-/> snacks.terminal과 별개로, 손에 익은 floaterm을 같이 붙였습니다. <C-;>로 토글하며 둘은 충돌하지 않고 병존합니다.
lua/plugins/lang-extras.lua
LazyExtras를 일괄 활성화했습니다.
return {
{ import = "lazyvim.plugins.extras.lang.go" },
{ import = "lazyvim.plugins.extras.lang.typescript" },
{ import = "lazyvim.plugins.extras.lang.markdown" },
{ import = "lazyvim.plugins.extras.lang.json" },
{ import = "lazyvim.plugins.extras.lang.yaml" },
{ import = "lazyvim.plugins.extras.lang.python" },
}
이 한 파일이 mason에게 marksman, gopls, ts_ls, pyright, ruff, jsonls, yamlls를 자동 설치하도록 위임합니다. 직전 셋업에서 손으로 동기화하던 그 영역입니다.
사용자 영역 추가
keymaps (config/keymaps.lua)
LazyVim 기본 키맵으로 이미 커버되는 건 이식하지 않았습니다. 기존에 손에 박힌 두 개만 살렸습니다.
| 키 | 동작 |
|---|---|
<leader>h | search highlight 끄기 |
<C-;> | floaterm 토글 |
이미 LazyVim이 잡아주는 것: <leader>e neo-tree, <C-h/j/k/l> 패인 이동, < > visual indent stay, <leader>ff 파일 찾기 등. 전체는 LazyVim 키맵 치트시트 참고합니다.
마크다운 filetype 동작 (config/autocmds.lua)
vim.api.nvim_create_autocmd("FileType", {
pattern = "markdown",
callback = function()
vim.opt_local.wrap = true
vim.opt_local.linebreak = true
vim.opt_local.conceallevel = 2
vim.opt_local.spell = false
vim.opt_local.cursorline = true
vim.opt_local.signcolumn = "no"
end,
})
| 옵션 | 효과 |
|---|---|
wrap = true | 한글 긴 줄 자동 래핑 |
linebreak = true | 단어 경계에서만 래핑 (어절 중간 잘림 방지) |
conceallevel = 2 | 마크업 문자(**, # 등) 숨김 (실제로는 render-markdown이 3으로 덮어씀 — 더 강한 숨김. 의도된 동작) |
spell = false | 한글 문서에서 영어 spell 체크 끔 |
cursorline = true | 현재 줄 강조 (긴 문서 위치 추적) |
signcolumn = "no" | 좌측 여백 줄여 본문 폭 확보 |
클립보드는 별도 설정 없음
비주얼 모드에서 y만 눌러도 macOS 시스템 클립보드로 복사됩니다. LazyVim 15.x가 clipboard=unnamedplus를 기본값으로 잡아주기 때문입니다.
직전 수동 셋업에서는 제 setup 글에 적었듯 opt.clipboard = "unnamedplus" 한 줄을 직접 넣어야 했는데, distro 전환 후에는 이 줄도 지웠습니다. + 레지스터(시스템 클립보드)와 무명 레지스터(")가 자동 연결돼서 y/p가 양방향 동기화됩니다.
확인:
:set clipboard?
→ clipboard=unnamedplus 출력되면 OK.
provider 레벨 진단:
:checkhealth provider
또는 직접:
:let @+ = 'test'
→ 다른 앱에서 Cmd+V 했을 때 test가 붙으면 provider 정상.
tmux 안에서만 안 될 때는 ~/.tmux.conf에 OSC 52 전달 설정이 필요할 수 있습니다.
set -g set-clipboard on
macOS 로컬 tmux + pbcopy 조합은 보통 이 설정 없이도 동작합니다. SSH 원격 nvim에서 OSC 52 핸들링이 깨지는 환경이라면 LazyVim 기본값을 의도적으로 끄고 싶을 수 있습니다 — options.lua에 vim.opt.clipboard = "".
의존성 (brew 설치)
LazyVim 본체와 무관하게 PATH에 있어야 하는 외부 도구입니다.
| 도구 | 용도 |
|---|---|
| ripgrep | 빠른 grep (snacks.picker <leader>sg) |
| fd | 빠른 파일 찾기 (snacks.picker <leader>ff) |
| lazygit | <leader>gg git TUI |
| node, npm | LSP 서버들 (ts_ls, yamlls 등) |
| python3 | pynvim, mason 도구 |
mason이 자동 설치하는 도구는 처음 해당 언어 파일을 열 때 받아옵니다: marksman, gopls, ts_ls, pyright, ruff, jsonls, yamlls, lua_ls, markdownlint-cli2, prettier, stylua, gofumpt, goimports, golangci-lint, shfmt 등입니다.
검증 결과
| 항목 | 결과 |
|---|---|
| Lazy sync | 통과 (42개 플러그인 설치) |
| 세 colorscheme 로드 | 통과 (solarized, everforest, gruvbox-material) |
| 마크다운 autocmd 적용 | 통과 (ft=markdown wrap=true cole=3 spell=false) |
| nvim startup 에러 | 없음 |
전부 첫 실행에 떨어졌습니다. 백업해 둔 .backup-2026-05-07은 한 달 정도 묵혀 두고, 회귀가 없으면 정리할 예정입니다.
사용 팁
<Space>누르고 1초 대기 → which-key가 카테고리별 메뉴를 띄웁니다. 가장 빠른 키맵 학습 방법:LazyExtras→ 추가 언어팩 ON/OFF UI:Mason→ LSP/포매터/린터 설치 상태:LazyHealth,:checkhealth→ 의존성/문제 진단:colorscheme <name>으로 테마 즉시 전환. 영구화는lua/plugins/colorscheme.lua마지막 블록의colorscheme = "..."변경:RenderMarkdown toggle— 렌더링을 잠깐 끄고 원본 마크다운(**bold**,# H1)을 보고 싶을 때
정리
수동 lazy.nvim 셋업은 잘 동작했고, 그 자체로 충분히 좋았어요. 다만 “제가 직접 관리해야 하는 것"의 표면적이 넓을수록 새 머신/새 언어를 붙일 때마다 작은 의식이 늘어났습니다. distro는 그 표면적을 줄여줍니다. 자동으로 처리될 수 있는 영역(LSP 자동완성, 포매팅, 치트시트, Git UI)을 일괄로 위임하고, 사용자는 “취향 차이가 나는 부분"에만 집중합니다.
LazyVim의 좋은 점은 lazy.nvim 위에 그대로 얹혀 있다는 점입니다. 빠지더라도 ~/.config/nvim을 통째로 갈아엎지 않아도 되고, 위 백업 절차로 언제든 직전 상태로 돌아올 수 있습니다. 그 안전망 위에서 가볍게 시도해볼 만한 전환이었어요.
키맵은 별도 글로 분리했어요: LazyVim 키맵 치트시트.