zettelkasten.nvim

July 11, 2026 ยท View on GitHub

Run Tests GitHub License GitHub Issues or Pull Requests GitHub commit activity GitHub Release luarocks

A Zettelkasten note-taking plugin for Neovim, written in Lua.

๐Ÿ“˜ Intro

zettelkasten.nvim brings Zettelkasten-style note-taking into Neovim. Notes are stored as Markdown files with timestamp-based IDs, and the plugin provides a browser window, tags sidebar, reference/backlink tracking, completion, and integrations with picker.nvim, telescope.nvim, calendar.nvim, and chat.nvim.

โœจ Features

  • ๐Ÿ“ Zettelkasten Notes - Create notes with timestamp-based IDs (YYYY-MM-DD-HH-MM-SS.md)
  • ๐Ÿ—‚๏ธ Note Browser - Browse all notes in a dedicated window with customizable format
  • ๐Ÿท๏ธ Tags Sidebar - Foldable tag tree for visual tag-based filtering
  • ๐Ÿ”— References & Backlinks - Automatic [[note-id]] reference detection and backlink tracking
  • โœ๏ธ Completion - Note ID and tag completion via completefunc and tagfunc
  • ๐Ÿ“‹ Quickfix Integration - List back references in the quickfix/location window
  • ๐Ÿ–ผ๏ธ Clipboard Image Paste - Paste images from clipboard directly into notes (macOS/Linux/Windows)
  • ๐Ÿ” Multi-Picker Support - Integrates with picker.nvim and telescope.nvim
  • ๐Ÿ“… Calendar Integration - Highlights dates with notes via calendar.nvim
  • ๐Ÿ’ฌ Chat Integration - Create, retrieve, and update notes via chat.nvim
  • ๐Ÿงฉ Note Templates - Create notes from pre-defined templates

๐Ÿ“ฆ Installation

Using nvim-plug:

require('plug').add({
    {
        'wsdjeg/zettelkasten.nvim',
        config = function()
            require('zettelkasten').setup({
                notes_path = '~/.zettelkasten',
                template_dir = '~/.zettelkasten_template',
                preview_command = 'pedit',
                browseformat = '%f - %h [%r Refs] [%b B-Refs] %t',
            })
            vim.keymap.set('n', '<leader>mzb', '<cmd>ZkBrowse<cr>', { silent = true })
            vim.keymap.set('n', '<leader>mzn', '<cmd>ZkNew<cr>', { silent = true })
        end,
    },
})

Using LuaRocks:

luarocks install zettelkasten.nvim

๐Ÿ”ง Configuration

All options are passed to require('zettelkasten').setup({}):

OptionTypeDefaultDescription
notes_pathstring'~/.zettelkasten/'Directory where notes are stored
template_dirstring'~/.zettelkasten_template'Directory containing note templates
preview_commandstring'pedit'Vim command used for note preview
browseformatstring'%f - %h [%r Refs] [%b B-Refs] %t'Format string for the browser window (see Browser Format)
completion_kindstring'[zettelkasten]'Kind label shown in completion menu
browse_title_widthnumber30Max display width for note titles in the browser

โš™๏ธ Commands

CommandDescription
:ZkNewCreate a new zettelkasten note
:ZkBrowse [tags...]Open the note browser; optional tag arguments to filter
:ZkHover [-preview] [-return-lines] [word]Show note info in a notification; -preview opens preview window, -return-lines returns full content

โŒจ๏ธ Key Bindings

Browser Window

KeyDescription
F2Open the zettelkasten tags sidebar
<LeftRelease>Filter notes by the tag under cursor
<Enter> / gfOpen the note under cursor
Ctrl-lClear tag filter and reload all notes
Ctrl-] / KPreview note via keywordprg (:ZkHover -preview)
[IList back references in the quickfix window
Ctrl-x Ctrl-uComplete note ID or tags (insert mode)
qClose the browser window

Tags Sidebar

KeyDescription
<Enter>Filter browser notes by the tag under cursor
<LeftRelease>Filter by tag, or toggle fold on fold markers
F2 / qClose the tags sidebar

Note Buffer

KeyDescription
<Leader>pPaste image from clipboard into the note
KHover note info (:ZkHover)
[IList back references in the quickfix window
Ctrl-]Jump to [[note-id]] reference via tagfunc
Ctrl-x Ctrl-uComplete note ID or tags (insert mode)

๐ŸŽจ Browser Format

The browseformat option controls how each note is displayed in the browser window. The following modifiers are supported:

ModifierDescription
%fFile name (e.g. 2024-01-15-10-30-00.md)
%hNote title (padded/truncated to browse_title_width)
%dNote ID (timestamp)
%rNumber of references (outgoing [[links]])
%bNumber of back references (incoming links)
%tSpace-separated tags

๐Ÿ” Picker Integration

zettelkasten.nvim provides sources for picker.nvim:

:Picker zettelkasten
:Picker zettelkasten_tag
:Picker zettelkasten_template
SourceDescription
zettelkastenFuzzy find notes, open or insert note ID
zettelkasten_tagFuzzy find tags, filter browser by selection
zettelkasten_templateFuzzy find templates, create note from selection

Key bindings in picker sources:

KeyDescription
<Enter>Default action (open note / filter / create)
<C-y>Insert selected note's ID at cursor position

๐Ÿ”ญ Telescope Integration

zettelkasten.nvim also provides extensions for telescope.nvim:

require('telescope').load_extension('zettelkasten')
require('telescope').load_extension('zettelkasten_tags')
require('telescope').load_extension('zettelkasten_template')
CommandDescription
:Telescope zettelkastenFind and open notes
:Telescope zettelkasten_tagsFind and filter by tags
:Telescope zettelkasten_templateFind and create from templates

๐Ÿ“… Calendar Extension

zettelkasten.nvim provides an extension for calendar.nvim. It highlights dates that have zettelkasten notes associated with them.

When pressing <Enter> on a date in the calendar, the following actions are available:

  1. Create a daily note - Creates a new note with the selected date
  2. Browse daily notes - Opens the browser filtered by the selected date

๐Ÿ’ฌ Chat Integration

zettelkasten.nvim provides three tools for chat.nvim:

Create Notes

@zk create <title>

Creates a new zettelkasten note with automatic ID generation and tag support.

Parameters:

  • title (string, required): The title of the note
  • content (string, required): The main body content of the note
  • tags (array of strings, optional): Tags for categorizing the note (e.g., ["programming", "vim"])

The note file is formatted as:

# <id> <title>

tags: #tag1 #tag2

<content>

Retrieve Notes

@zk get <tags>

Retrieves zettelkasten notes by tags. Returns a JSON array of matching notes with file_name and title fields.

Update Notes

@zk update <id> <action> [parameters]

Updates an existing zettelkasten note with partial modifications โ€” no need to pass the full note content.

Parameters:

  • id (string, required): The note ID (e.g., "2024-01-15-10-30-00")
  • action (string, required): One of the following:
ActionDescriptionExtra Parameters
update_titleChange the note title (ID preserved)title (string, required)
add_tagsAdd tags (duplicates skipped)tags (string[], required)
remove_tagsRemove tags (removes line if empty)tags (string[], required)
replace_textFind/replace in note bodyold_text (string), new_text (string)

Tags can be provided with or without # prefix. For replace_text, the title line (line 1) is skipped. Use empty new_text to delete text.

Examples:

@zk update id="2024-01-15-10-30-00" action="update_title" title="New Title"
@zk update id="2024-01-15-10-30-00" action="add_tags" tags=["python", "web"]
@zk update id="2024-01-15-10-30-00" action="remove_tags" tags=["old-tag"]
@zk update id="2024-01-15-10-30-00" action="replace_text" old_text="old code" new_text="new code"

๐Ÿž Debug

Debug zettelkasten.nvim with logger.nvim:

require('plug').add({
    {
        'wsdjeg/zettelkasten.nvim',
        depends = { { 'wsdjeg/logger.nvim' } },
    },
})

๐Ÿ“ธ Screenshots

๐Ÿ“ฃ Self-Promotion

Like this plugin? Star the repository on GitHub.

Love this plugin? Follow me on GitHub.

๐Ÿ™ Credits

This plugin is forked from Furkanzmc/zettelkasten.nvim.

New features added in this fork:

  • Tags sidebar with foldable tag tree for visual filtering
  • Tag completion in completefunc (detects # prefix context)
  • Clipboard image paste (macOS / Linux / Windows)
  • Note templates and custom-date note creation via zknew(opt)
  • Calendar.nvim, picker.nvim, telescope.nvim, and chat.nvim integrations
  • LuaRocks support and release-please automation

Improvements over upstream:

  • Nil-safety and file-handle cleanup in note parsing
  • Duplicate note ID guard in set_note_id
  • Read-only browser buffer with richer keybindings (q, <Enter>, <C-l>, <F2>)
  • CJK-aware title truncation in the browser formatter
  • Simplified config (module-level fields instead of config.get())
  • Comprehensive unit test suite with luaunit

๐Ÿ’ฌ Feedback

If you encounter any bugs or have suggestions, please file an issue in the issue tracker.