bookmarks.nvim

July 19, 2025 ยท View on GitHub

A Neovim plugin for managing line bookmarks with Telescope integration and SQLite storage. Mark, organize, and quickly navigate between important locations in your codebase.

Search and Navigation

Features

  • ๐Ÿ”– Add/remove bookmarks with visual indicators
  • ๐ŸŒŸ Line highlighting for bookmarked lines
  • ๐Ÿš€ Fast SQLite-based persistent storage
  • ๐Ÿ” Telescope integration for browsing and searching bookmarks
  • โŒจ๏ธ Intuitive default keymaps
  • ๐Ÿ”Ž Fuzzy search through bookmarks by filename or content
  • โšก Async file preview loading
  • ๐Ÿงญ Next/Previous bookmark navigation within files
  • ๐ŸŽฏ Jump directly to bookmarked locations
  • ๐Ÿ—‚๏ธ Multiple bookmark lists: Organize bookmarks into named lists for different projects, features, or workflows
  • ๐Ÿงฉ List management UI: Create, switch, rename, and delete lists via commands or Telescope

bookmarks.nvim vs. Native Vim Marks

While Vim's native marks (ma, 'a) are useful for temporary navigation, bookmarks.nvim provides a more robust, feature-rich, and persistent bookmarking system.

FeatureNative Vim Marksbookmarks.nvim
StoragePlain text (.viminfo/shada)SQLite Database for structured, queryable, and persistent storage
ScopeLocal (per-file) or Global (cross-file)Project-aware: Bookmarks are tied to a project root
Branch-specificNoYes: Bookmarks can be isolated per Git branch and toggled at runtime
DataFile path, line, and column onlyRich metadata: line content, timestamp, project info
UICommand-based (:marks)Interactive UI: Telescope integration for fuzzy search, browsing, and live previews
PersistenceOnly global marks (A-Z) persist across sessionsAll bookmarks are persistent by default
ManagementManual, must remember mark lettersCentralized API: Add, remove, list, and navigate bookmarks
DependenciesNone (core feature)Requires sqlite.lua and telescope.nvim
Multiple ListsNoYes: Organize bookmarks into named lists, switch between them
List Management UINoYes: Create, switch, rename, delete lists via commands or Telescope

Requirements

Installation

Using lazy.nvim:

{
    "heilgar/bookmarks.nvim",
    dependencies = {
        "kkharji/sqlite.lua",
        "nvim-telescope/telescope.nvim",
        "nvim-lua/plenary.nvim",
    },
    config = function()
        require("bookmarks").setup({
            -- your configuration comes here
            -- or leave empty to use defaults
            default_mappings = true,
            db_path = vim.fn.stdpath('data') .. '/bookmarks.db'
        })
        require("telescope").load_extension("bookmarks")
    end,
    cmd = {
        "BookmarkAdd",
        "BookmarkRemove",
        "Bookmarks"
    },
    keys = {
        { "<leader>ba", "<cmd>BookmarkAdd<cr>", desc = "Add Bookmark" },
        { "<leader>br", "<cmd>BookmarkRemove<cr>", desc = "Remove Bookmark" },
        { "<leader>bj", desc = "Jump to Next Bookmark" },
        { "<leader>bk", desc = "Jump to Previous Bookmark" },
        { "<leader>bl", "<cmd>Bookmarks<cr>", desc = "List Bookmarks" },
        { "<leader>bs", desc = "Switch Bookmark List" },
    },
}

Configuration

require("bookmarks").setup({
    -- Storage configuration
    db_path = vim.fn.stdpath('data') .. '/bookmarks.db',  -- Path to SQLite database

    -- Branch configuration
    use_branch_specific = false,  -- Enable/disable branch-specific bookmarks (can be toggled at runtime)

    -- Keymaps configuration
    default_mappings = true,  -- Set to false to disable default keymaps

    -- Custom mappings example (if default_mappings = false):
    mappings = {
        add = "ma",          -- Add bookmark at current line
        delete = "md",       -- Delete bookmark at current line
        list = "ml",         -- List all bookmarks
    }
})

Usage

Commands

  • :BookmarkAdd - Add bookmark at current line
  • :BookmarkRemove - Remove bookmark at current line
  • :Bookmarks - Open Telescope to browse bookmarks
  • :BookmarksToggleBranchScope - Toggle branch-specific bookmarks on/off

List Management

  • :BookmarkListCreate <name> โ€” Create a new bookmark list
  • :BookmarkListSwitch <name|global> โ€” Switch to a list (or global)
  • :BookmarkListRename <old> <new> โ€” Rename a list
  • :BookmarkListDelete <name> โ€” Delete a list (bookmarks reassigned to global)
  • :BookmarkListShow โ€” Show all lists, with the active one marked

Telescope List Management

  • <leader>bs โ€” Open Telescope picker to switch, create, rename, or delete lists interactively
  • :Telescope bookmarks lists โ€” Fuzzy manage lists (switch, create, rename, delete)
    • <CR>: Switch to list
    • <C-n>: Create new list
    • <C-r>: Rename list
    • <C-d>: Delete list

Default Keymaps

  • <leader>ba - Add bookmark
  • <leader>br - Remove bookmark
  • <leader>bj - Jump to next bookmark in file
  • <leader>bk - Jump to previous bookmark in file
  • <leader>bl - List bookmarks (opens Telescope, filtered by active list)
  • <leader>bs - Switch bookmark list (Telescope picker)

Inside Telescope bookmarks view:

  • <CR> - Jump to selected bookmark
  • <Del> - Delete selected bookmark

To disable default keymaps, set default_mappings = false in setup and define your own:

vim.keymap.set('n', '<your-keymap>', require('bookmarks.commands').add_bookmark)
vim.keymap.set('n', '<your-keymap>', require('bookmarks.commands').remove_bookmark)
vim.keymap.set('n', '<your-keymap>', require('bookmarks.navigation').jump_to_next)
vim.keymap.set('n', '<your-keymap>', require('bookmarks.navigation').jump_to_prev)
vim.keymap.set('n', '<your-keymap>', require('telescope').extensions.bookmarks.list)

Appearance

The plugin defines these highlight groups that you can customize:

  • BookmarkHighlight - Highlight for bookmarked lines
  • BookmarkSignHighlight - Highlight for the bookmark sign column indicator

Example of customizing highlights:

vim.api.nvim_set_hl(0, "BookmarkHighlight", {
    bg = "#3a3a3a",
    underline = true
})

vim.api.nvim_set_hl(0, "BookmarkSignHighlight", {
    fg = "#458588",
})

API

local bookmarks = require("bookmarks")

-- Add bookmark at current line
bookmarks.add_bookmark()

-- Remove bookmark at current line
bookmarks.remove_bookmark()

-- Navigate bookmarks in current file
bookmarks.jump_to_next()
bookmarks.jump_to_prev()

-- Jump to a specific bookmark
bookmarks.jump_to_bookmark(filename, line_number)

-- Get all bookmarks
local storage = require("bookmarks.storage")
local all_bookmarks = storage.get_bookmarks()

-- Get bookmarks for specific file
local file_bookmarks = storage.get_file_bookmarks(filename)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

Thanks to:

Screenshots

Bookmark Preview

Bookmark Preview Search and Navigation

Search for bookmarks by filename, content, or line number directly from the search prompt. The UI is designed for maximum readability with clear visual separation between entries.

The bookmarks viewer features a vertical layout with:

  • File preview at the top, with syntax highlighting and a visual indicator for the bookmarked line
  • Bookmark list in the middle showing line numbers, filenames, and bookmark content
  • Search prompt at the bottom for quick filtering

Branch-Specific Bookmarks

When use_branch_specific is enabled, bookmarks are stored and shown per Git branch. This means:

  • You only see bookmarks for the current branch in both buffer and Telescope views.
  • Bookmarks added on one branch are not visible on another branch.
  • When toggled off, all bookmarks (regardless of branch) are shown.
  • You can toggle this at runtime with :BookmarksToggleBranchScope or <leader>bt.

This is useful for workflows where you want to keep bookmarks isolated to specific features or tasks per branch.

Statusline Helper

You can show the current bookmarks scope (global or branch) in your statusline using the built-in helper:

Vanilla Neovim

Add this to your init.lua:

vim.o.statusline = "%f %h%m%r %=%{v:lua.require('bookmarks').status()}"

lualine.nvim

If you use lualine.nvim:

require('lualine').setup {
  sections = {
    lualine_c = {
      'filename',
      { function() return require('bookmarks').status() end }
    },
    -- ... other sections ...
  }
}

This will show Bookmarks: branch=my-feature or Bookmarks: global in your statusline, depending on the current mode.