Skip to main content

What are EmmyLua Annotations?

EmmyLua annotations are special comments that provide type information and documentation to your Lua code. They enable static type checking, improved auto-completion, and better code documentation without changing how your Lua code runs. Annotations are written as comments using the ---@ prefix, making them completely invisible to the Lua runtime while providing rich information to language servers and development tools.
---@class User
---@field id number User ID
---@field name string Username
---@field email string Email address

---@param name string Username
---@param age number User age
---@return User User object
function createUser(name, age)
    return {id = generateId(), name = name, age = age}
end

Why Use Annotations?

Annotations provide several key benefits for Lua development:

Type Safety

Catch type errors before runtime by providing explicit type information:
---@param x number
---@param y number
---@return number
function add(x, y)
    return x + y
end

-- The analyzer will warn about this:
add("5", "10")  -- Warning: expected number, got string

Enhanced Auto-Completion

Get intelligent suggestions based on type information:
---@class Vector
---@field x number
---@field y number
---@field magnitude fun(self: Vector): number

---@type Vector
local vec = createVector(3, 4)

-- Auto-completion now knows vec has x, y, and magnitude()
vec.  -- Shows: x, y, magnitude

Better Documentation

Document your code inline with type-aware descriptions:
---@param data table Raw data to process
---@param options? {timeout?: number, retries?: number} Configuration options
---@return boolean success Whether processing succeeded
---@return string? error Error message if failed
function processData(data, options)
    -- Implementation
end

Improved Refactoring

Rename symbols, find references, and refactor with confidence:
---@class Database
---@field connect fun(self: Database): boolean
---@field query fun(self: Database, sql: string): table

-- Renaming Database will update all references
---@type Database
local db = Database.new()
Annotations are completely optional and non-invasive. You can add them gradually to existing projects without affecting runtime behavior.

Annotation Systems

The EmmyLua Analyzer supports two annotation formats:

EmmyLua Annotations

The original and most widely used annotation format, developed for the EmmyLua plugin:
---@class Animal
---@field name string Animal name
---@field species string Species

---@param name string
---@param species string
---@return Animal
function Animal.new(name, species)
    return {name = name, species = species}
end

LuaCATS Annotations

A documentation-focused annotation standard that’s also supported:
--- Create a new animal
---@class Animal
---@field name string Animal name
---@field species string Species
local Animal = {}
Both annotation formats are fully supported by the EmmyLua Analyzer. You can even mix them in the same project, though consistency is recommended.

Benefits Over Other Systems

Compared to Runtime Type Checking

EmmyLua Annotations:
  • Zero runtime overhead
  • Catch errors during development
  • No additional dependencies
  • Works with existing Lua code
Runtime Type Checking:
  • Performance impact
  • Only catches errors when code executes
  • Requires additional libraries
  • May need code modifications

Compared to External Documentation

EmmyLua Annotations:
  • Documentation lives with code
  • Always up-to-date with implementation
  • Type-aware and machine-readable
  • Enables IDE features
External Documentation:
  • Can become outdated
  • Separated from code
  • Not machine-readable
  • No IDE integration

Compared to TypeScript/TypeScriptToLua

EmmyLua Annotations:
  • Pure Lua syntax
  • No compilation step
  • Works with any Lua runtime
  • Gradual adoption
TypeScript:
  • Requires compilation
  • Different syntax to learn
  • May have compatibility issues
  • All-or-nothing approach

Getting Started

Start using annotations in your Lua projects in three simple steps:

1. Install EmmyLua Analyzer

Install the language server in your editor (VS Code, Neovim, etc.):
# For VS Code
code --install-extension sumneko.lua

# Or use your editor's extension manager

2. Add Your First Annotation

Start with simple type declarations:
---@type string
local userName = "John"

---@type number
local userAge = 25

---@type boolean
local isActive = true

3. Document Functions

Add parameter and return type information:
---@param name string
---@param age number
---@return table
function createUser(name, age)
    return {name = name, age = age}
end

4. Define Classes

Create structured types for your objects:
---@class Config
---@field host string Server hostname
---@field port number Server port
---@field timeout? number Connection timeout in seconds

---@type Config
local config = {
    host = "localhost",
    port = 8080,
    timeout = 30
}

Next Steps

Now that you understand what annotations are and why they’re useful, learn about:

Annotation Syntax

Learn the syntax rules and formatting for writing annotations

Type System

Understand types, unions, generics, and type expressions

Class Definitions

Define classes, fields, and object structures

Function Annotations

Document parameters, returns, and overloads

Common Use Cases

API Documentation

---@class HTTPRequest
---@field method 'GET'|'POST'|'PUT'|'DELETE'
---@field url string
---@field headers? table<string, string>
---@field body? string

---@param request HTTPRequest
---@param options? {timeout?: number, retries?: number}
---@return boolean success
---@return string? response
---@return string? error
function httpRequest(request, options)
    -- Implementation
end

Library Type Definitions

---@class JSON
local json = {}

---@param value any Value to encode
---@param options? {pretty?: boolean, indent?: string}
---@return string Encoded JSON string
function json.encode(value, options)
    -- Implementation
end

---@param str string JSON string to decode
---@return any Decoded value
---@return string? error Error message if parsing failed
function json.decode(str)
    -- Implementation
end

Configuration Objects

---@alias LogLevel 'debug'|'info'|'warn'|'error'

---@class Logger
---@field level LogLevel Current log level
---@field output fun(message: string): nil

---@param level LogLevel
---@param message string
function log(level, message)
    -- Implementation
end
For a complete reference of all available annotations, see the Annotation Types.

Build docs developers (and LLMs) love