이 글은 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 키맵 치트시트.