Overview
Prerequisites
- Prior topics: 1 · Just Enough Nvim -- you should be comfortable opening, editing, and saving files before writing and running Lua scripts.
- Tools & environment: a macOS/Linux terminal; the standalone
luainterpreter installed (verify withlua -v) for running scripts outside Neovim. Lua is licensed MIT, a Tier-1 free-to-teach license (Neovim bundles its embedded Lua under the same MIT terms). - Assumed knowledge: basic terminal use. No prior programming language is required -- this is a first language for some readers.
Why this exists -- the big idea
3 · Extending Neovim configures Neovim in Lua, and
learning the config language and the editor-extension concept at the same time doubles the
difficulty -- so this primer gets you just enough Lua first, before you ever touch a .lua config
file. The one idea worth keeping if you forget everything else: a single structure, the table,
is Lua's array, map, object, and module all at once -- master the table and the rest of the
language is small.
Cross-cutting big idea: abstraction-and-its-cost -- Lua's one universal abstraction (the
table) buys you a tiny, learnable language, and the price is the specialized types (real arrays,
sets, structs, hash maps) a bigger language would hand you for free. Every design choice this
primer covers traces back to that trade.
Install and run your first script
Install the standalone Lua interpreter for your platform (macOS: brew install lua;
Debian/Ubuntu: install your distribution's current lua5.x package, or build from source at
lua.org/download.html), then confirm the version:
$ lua -v
Lua 5.5.0 Copyright (C) 1994-2025 Lua.org, PUC-RioLua's current major release is 5.5.0 (released 2025-12-22); the 5.4 line's latest patch is 5.4.8. Both are far ahead of the Lua dialect Neovim itself embeds -- more on that gap below.
A note on "Output" blocks: print() joins multiple values with a literal tab character, and
a handful of examples produce a trailing space before their final newline. Every "Output" block in
this primer was captured by actually running the script it follows, but this page's own markdown
rendering normalizes tabs to single spaces and trims trailing whitespace for readability. Trust the
.lua script's own -- => annotations and, best of all, lua example.lua on your own machine for
the byte-exact bytes -- the visible "Output" block is a faithful reading of that output, not
always a byte-for-byte terminal capture.
Every example in this primer is a complete, self-contained .lua file colocated under
learning/code/. The command you will run for almost every one of them is exactly this:
lua example.luaTwo families of exceptions, both deliberate and both teaching co-18 (Neovim's embedded Lua dialect):
- Example 72 demonstrates the global
unpack()function that exists in Lua 5.1 (and in LuaJIT, which targets 5.1 semantics) but was removed from standalone Lua 5.2 onward. Run it withluajit example.luainstead oflua example.lua-- running it with plainluareproduces the exact error a Neovim-only assumption would cause outside Neovim. - Examples 78-84 call the
vim.*API, which only exists inside a running Neovim process -- there is no standalone equivalent. Open Neovim and run:luafile example.luafrom inside the example's directory (or usenvim --headless -c "luafile example.lua" -c "qa!"to run one non-interactively).
How this primer is organized
- Beginner (Examples 1-26) -- core syntax and expressions: the eight basic types,
nil/falsetruthiness, local-vs-global scoping, arithmetic, string basics, comparisons, theand/oridioms, control flow (if/for/while/repeat), and the table literal's two faces (array and map). - Intermediate (Examples 27-58) -- varargs, the
tablelibrary (insert/remove/concat/sort), thestringlibrary'sformat/sub/find/match/gmatch/gsub, generic-foriterators, closures, recursion and higher-order functions, metatables for defaults, inheritance-style fallback,__tostring, and operator overloading, modules viarequire, and basicpcallerror handling. - Advanced (Examples 59-84) -- the rest of error handling (
errorwith non-string values,assert,xpcallwith a traceback handler, error levels), the remaining metamethods (__eq,__call), a full prototype-based OOP class/inheritance/override chain, coroutines end to end, the Lua-5.1-vs-later dialect gap Neovim actually lives in, and the sevenvim.*API calls (table merging, mapping, keymaps, options, buffer lines, inspection, string splitting) every later Neovim-extension topic leans on.
Every example cites the concept (co-NN) it exercises, and every claim about Lua's versions,
license, and Neovim's embedded dialect traces to lua.org, luajit.org, and Neovim's own
runtime/doc/runtime/lua sources, web-verified 2026-07-12 and re-confirmed 2026-07-14.
Scope: just enough, not comprehensive
This is a Primer, not a comprehensive Lua reference: it covers exactly the language surface
3 · Extending Neovim depends on, and deliberately
excludes LPeg, the utf8 library, string.pack/string.unpack, os.date formatting, file and
process I/O beyond the io.write calls already shown, __newindex/__lt/__le and the rest of
the metamethod family beyond what OOP and operator
overloading require, weak tables, userdata, the C API, and LuaRocks package management. If a Lua
feature is not exercised by a later topic in this journey, it is out of scope here on purpose, not
by oversight.
← Previous: 1 · Just Enough Nvim · Next: Beginner Examples →
Last updated July 13, 2026