Skip to main content

Language and Data Plugins

These plugins handle specialized workflows: querying databases, testing REST APIs, previewing Markdown, running tests, and editing specific file formats.

1. vim-dadbod — Database UI Inside Neovim

The most complete database client for Neovim. Supports PostgreSQL, MySQL, SQLite, MongoDB, Redis, and more:

lua/plugins/data.lua
return {
{
"tpope/vim-dadbod",
cmd = { "DB", "DBUI" },
},
{
"kristijanhusak/vim-dadbod-ui",
dependencies = {
"tpope/vim-dadbod",
{ "kristijanhusak/vim-dadbod-completion", ft = { "sql", "mysql", "plsql" } },
},
cmd = { "DBUI", "DBUIToggle", "DBUIAddConnection", "DBUIFindBuffer" },
keys = {
{ "<leader>Du", "<cmd>DBUIToggle<cr>", desc = "Toggle Database UI" },
{ "<leader>Df", "<cmd>DBUIFindBuffer<cr>", desc = "Find DB buffer" },
{ "<leader>Dr", "<cmd>DBUIRenameBuffer<cr>", desc = "Rename DB buffer" },
{ "<leader>Dq", "<cmd>DBUILastQueryInfo<cr>", desc = "Last query info" },
},
init = function()
vim.g.db_ui_use_nerd_fonts = 1
vim.g.db_ui_auto_execute_table_helpers = 1
vim.g.db_ui_icons = {
expanded = { db = "▾ ", buffers = "▾ ", saved_queries = "▾ ", schemas = "▾ ", schema = "▾ ", tables = "▾ ", table = "▾ " },
collapsed = { db = "▸ ", buffers = "▸ ", saved_queries = "▸ ", schemas = "▸ ", schema = "▸ ", tables = "▸ ", table = "▸ " },
saved_query = " ",
new_query = " ",
tables = " ",
buffers = " ",
add_connection = " ",
connection_ok = "✓ ",
connection_error = "✕ ",
}
end,
},
}

Adding Connections

Connection strings go in ~/.local/share/db_ui/connections.json or via environment variables:

~/.local/share/db_ui/connections.json
[
{
"name": "Local PostgreSQL",
"url": "postgresql://user:password@localhost:5432/mydb"
},
{
"name": "Production MySQL",
"url": "mysql://user:password@prod-host:3306/myapp"
},
{
"name": "SQLite",
"url": "sqlite:///path/to/database.db"
}
]

Usage

<leader>Du        → open DBUI sidebar
Enter → expand connection
Enter on table → open table helper queries
gq on query → run query, results show below
<C-j/k> → navigate results
:DB {url} {query} → run query directly from cmdline

vim-dadbod-completion with nvim-cmp

Add to nvim-cmp sources for sql files:
-- In your cmp setup, add under filetype config:
cmp.setup.filetype({ "sql", "mysql", "plsql" }, {
sources = cmp.config.sources({
{ name = "vim-dadbod-completion" },
{ name = "buffer" },
}),
})

2. rest.nvim — REST API Client

Test REST APIs directly from .http files inside Neovim:

{
"rest-nvim/rest.nvim",
ft = "http",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<leader>rr", "<Plug>RestNvim", ft = "http", desc = "Run REST request" },
{ "<leader>rp", "<Plug>RestNvimPreview", ft = "http", desc = "Preview REST request" },
{ "<leader>rl", "<Plug>RestNvimLast", ft = "http", desc = "Re-run last request" },
},
opts = {
result_split_horizontal = false,
result_split_in_place = false,
skip_ssl_verification = false,
encode_url = true,
highlight = {
enabled = true,
timeout = 150,
},
result = {
show_url = true,
show_curl_command = false,
show_http_info = true,
show_headers = true,
show_statistics = false,
formatters = {
json = "jq",
html = function(body)
return vim.fn.system({ "tidy", "-i", "-q", "-" }, body)
end,
},
},
jump_to_request = false,
env_file = ".env",
custom_dynamic_variables = {},
yank_dry_run = true,
search_back = true,
},
},

Writing .http Files

api-test.http
# Variables from .env file
@baseUrl = https://api.example.com
@token = {{$dotenv TOKEN}}

### Get all users
GET {{baseUrl}}/users
Accept: application/json
Authorization: Bearer {{token}}

### Create a user
POST {{baseUrl}}/users
Content-Type: application/json
Authorization: Bearer {{token}}

{
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}

### Update user
PUT {{baseUrl}}/users/1
Content-Type: application/json

{
"name": "Alice Updated"
}

### Delete user
DELETE {{baseUrl}}/users/1

Dynamic Variables

### Auto-generated UUID and timestamp
POST {{baseUrl}}/items
Content-Type: application/json

{
"id": "{{$guid}}",
"created_at": "{{$datetime iso8601}}",
"random_number": {{$randomInt 1 100}}
}

3. markdown-preview.nvim — Live Markdown in Browser

{
"iamcco/markdown-preview.nvim",
cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
ft = { "markdown" },
build = function() vim.fn["mkdp#util#install"]() end,
keys = {
{ "<leader>mp", "<cmd>MarkdownPreviewToggle<cr>", desc = "Toggle Markdown preview" },
},
init = function()
vim.g.mkdp_auto_start = 0 -- don't auto-open on enter
vim.g.mkdp_auto_close = 1 -- auto-close on buffer leave
vim.g.mkdp_refresh_slow = 0 -- refresh as you type
vim.g.mkdp_command_for_global = 0
vim.g.mkdp_open_to_the_world = 0
vim.g.mkdp_browser = "" -- use system browser
vim.g.mkdp_echo_preview_url = 0
vim.g.mkdp_preview_options = {
mkit = {},
katex = {}, -- math: katex
uml = {}, -- plantuml diagrams
maid = {}, -- mermaid diagrams
disable_sync_scroll = 0,
sync_scroll_type = "middle",
hide_yaml_meta = 1,
sequence_diagrams = {},
flowchart_diagrams = {},
content_editable = false,
disable_filename = 0,
toc = {},
}
vim.g.mkdp_markdown_css = ""
vim.g.mkdp_highlight_css = ""
vim.g.mkdp_port = ""
vim.g.mkdp_page_title = "「${name}」"
vim.g.mkdp_images_path = ""
vim.g.mkdp_filetypes = { "markdown" }
vim.g.mkdp_theme = "dark"
end,
},

Alternative: render-markdown.nvim (Inline rendering)

{
"MeanderingProgrammer/render-markdown.nvim",
dependencies = { "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" },
ft = { "markdown", "norg", "rmd", "org", "codecompanion", "Avante" },
opts = {
code = {
sign = false,
width = "block",
right_pad = 1,
},
heading = {
sign = false,
icons = { "󰲡 ", "󰲣 ", "󰲥 ", "󰲧 ", "󰲩 ", "󰲫 " },
},
},
},

4. neotest — Universal Test Runner

{
"nvim-neotest/neotest",
dependencies = {
"nvim-lua/plenary.nvim",
"antoinemadec/FixCursorHold.nvim",
"nvim-treesitter/nvim-treesitter",
-- Adapters for your languages:
"nvim-neotest/neotest-python",
"nvim-neotest/neotest-jest",
"marilari88/neotest-vitest",
"olimorris/neotest-phpunit",
"rcasia/neotest-bash",
},
keys = {
{ "<leader>tr", function() require("neotest").run.run() end, desc = "Run nearest test" },
{ "<leader>tf", function() require("neotest").run.run(vim.fn.expand("%")) end, desc = "Run test file" },
{ "<leader>ta", function() require("neotest").run.run(vim.loop.cwd()) end, desc = "Run all tests" },
{ "<leader>td", function() require("neotest").run.run({ strategy = "dap" }) end, desc = "Debug nearest test" },
{ "<leader>ts", function() require("neotest").summary.toggle() end, desc = "Toggle test summary" },
{ "<leader>to", function() require("neotest").output.open({ enter = true, auto_close = true }) end, desc = "Show test output" },
{ "<leader>tO", function() require("neotest").output_panel.toggle() end, desc = "Toggle output panel" },
{ "<leader>tS", function() require("neotest").run.stop() end, desc = "Stop test" },
{ "]t", function() require("neotest").jump.next({ status = "failed" }) end, desc = "Next failed test" },
{ "[t", function() require("neotest").jump.prev({ status = "failed" }) end, desc = "Prev failed test" },
},
config = function()
require("neotest").setup({
adapters = {
require("neotest-python")({
dap = { justMyCode = false },
runner = "pytest", -- pytest | unittest
python = ".venv/bin/python", -- or system python
}),
require("neotest-jest")({
jestCommand = "npx jest",
jestConfigFile = "jest.config.js",
env = { CI = "true" },
cwd = function() return vim.fn.getcwd() end,
}),
require("neotest-vitest"),
require("neotest-phpunit")({
phpunit_cmd = function()
return "vendor/bin/phpunit"
end,
}),
require("neotest-bash"),
},
consumers = {},
icons = {
child_indent = "│",
child_prefix = "├",
collapsed = "─",
expanded = "╮",
failed = "",
final_child_indent = " ",
final_child_prefix = "╰",
non_collapsible = "─",
passed = "",
running = "",
running_animated = { "/", "|", "\\", "-", "/", "|", "\\", "-" },
skipped = "",
unknown = "",
watching = "",
},
status = {
enabled = true,
signs = true,
virtual_text = false,
},
output = {
enabled = true,
open_on_run = "short",
},
output_panel = {
enabled = true,
open = "botright split | resize 15",
},
quickfix = {
enabled = true,
open = false,
},
})
end,
},

5. overseer.nvim — Task Runner

Run build tasks, scripts, and watchers from Neovim with rich output:

{
"stevearc/overseer.nvim",
cmd = {
"OverseerOpen", "OverseerClose", "OverseerToggle",
"OverseerSaveBundle", "OverseerLoadBundle",
"OverseerDeleteBundle", "OverseerRunCmd",
"OverseerRun", "OverseerInfo", "OverseerBuild",
"OverseerQuickAction", "OverseerTaskAction",
"OverseerClearCache",
},
keys = {
{ "<leader>oo", "<cmd>OverseerToggle<cr>", desc = "Task list" },
{ "<leader>or", "<cmd>OverseerRun<cr>", desc = "Run task" },
{ "<leader>oq", "<cmd>OverseerQuickAction<cr>", desc = "Quick action" },
{ "<leader>oi", "<cmd>OverseerInfo<cr>", desc = "Task info" },
{ "<leader>ob", "<cmd>OverseerBuild<cr>", desc = "Build" },
},
opts = {
task_list = {
direction = "bottom",
min_height = 10,
max_height = 25,
default_detail = 1,
},
},
},

What's Next