You played Roblox, World of Warcraft, Garry's Mod, or messed around with nginx - and you didn't even suspect that all this time you were using Lua. It's time to get to know each other properly.
Lua is the language that everyone says "ah, it's for games," and then it turns out that it lives in Redis, NGINX (OpenResty), Wireshark, Neovim, and a bunch of other places where you need a fast, easy-to-embed scripting engine.
The entire Lua interpreter weighs less than 300 KB. At the same time, Lua is consistently included in the top of the fastest scripting languages (LuaJIT generally flies at the C level in some benchmarks).

Variables: everything is simple, but there is a nuance
Default variables in Lua global. Yes, just like in JavaScript before "use strict". And yes, it's a trap.
-- Это глобальная переменная. Она видна ОТОВСЮДУ.
name = "Code"
-- А вот так — локальная. Используй local ВСЕГДА.
local age = 25
local is_cool = trueRule number one: always write local. If you forget, the variable leaks into the global scope, and then you'll spend two hours debugging why counter is reset in random places.
Data types: minimalism in all its glory
In Lua, there are 8 types. Eight. For comparison, in TypeScript you have more types than friends on LinkedIn.
local a = 42 -- number (и int, и float — всё number)
local b = "hello" -- string
local c = true -- boolean
local d = nil -- nil (отсутствие значения)
local e = {} -- table (массив, объект, словарь — всё в одном)
local f = print -- function (да, функции — это значения)The most important thing: table is the only data structure. Array? Table. Object? Table. Dictionary? Also a table. HashMap? Guess.
Tables: one type to rule them all
Table in Lua is a Swiss knife. Look:
-- Как массив (индексация с 1, а не с 0!)
local fruits = {"apple", "banana", "mango"}
print(fruits[1]) -- "apple" (не fruits[0]!)
-- Как словарь
local user = {
name = "Alexey",
level = "senior",
stack = {"Vue", "Nuxt", "Lua"}
}
print(user.name) -- "Alexey"
print(user["level"]) -- "senior"
-- Как и то, и другое одновременно (но лучше так не делай)
local chaos = {
"first",
name = "Chaos",
"second",
power = 9000
}Indexing from one — this is why C, Python and JS developers have a poker face for the first 30 minutes. But then you get used to it. I promise.
Conditions and cycles: classics of the genre
No curly braces. No elif. Just if, elseif, then and end:
local hp = 75
if hp <= 0 then
print("Game Over")
elseif hp < 30 then
print("Critically low HP!")
else
print("Everything is fine, we live")
endThe cycles are also without surprises:
-- Числовой for
for i = 1, 5 do
print("Iteration:", i)
end
-- While
local count = 0
while count < 3 do
print(count)
count = count + 1 -- Да, в Lua нет ++ и +=
end
-- Перебор таблицы
local heroes = {"Geralt", "Link", "Mario"}
for index, hero in ipairs(heroes) do
print(index .. ". " .. hero)
endMoment of pain: in Lua there is no +=, -=, ++. Every time you write count = count + 1 as in 2003. There is a proposal to add compound operators, but for now — accept it.
Functions: first-class citizens
Functions in Lua are full values. They can be stored in variables, passed as arguments, and returned from other functions:
-- Обычная функция
local function greet(name)
return "Hi, " .. name .. "!"
end
print(greet("World")) -- "Hello, World!"
-- Функция, которая возвращает функцию (замыкание!)
local function create_counter()
local count = 0
return function()
count = count + 1
return count
end
end
local counter = create_counter()
print(counter()) -- 1
print(counter()) -- 2
print(counter()) -- 3Lua supports multiple return values — without any arrays or objects:
local function get_user()
return "Alexey", 25, "frontend"
end
local name, age, role = get_user()
print(name) -- "Alexey"
print(role) -- "frontend"Strings: concatenation through ..
Forget about + for strings. In Lua, concatenation is ..:
local first = "Hello"
local second = "World"
print(first .. " " .. second) -- "Hello World"
-- Длина строки
print(# "Kodik") -- 10 (UTF-8 bytes, not characters!)
-- string.format — как printf, только в Lua
local msg = string.format("%s %d HP", "hero", 100)
print(msg) -- "The hero has 100 HP"Important: the # operator returns the length in bytes, not in characters. For Cyrillic, this is a trap — each letter takes up 2 bytes in UTF-8.
OOP: collecting from tables and metatables
Lua doesn't have classes out of the box. But there are metatables — a mechanism through which inheritance, operator overloading, and any object model in general can be implemented:
-- "Class" через таблицу
local Player = {}
Player.__index = Player
function Player.new(name, hp)
local self = setmetatable({}, Player)
self.name = name
self.hp = hp
return self
end
function Player:take_damage(amount)
self.hp = self.hp - amount
if self.hp <= 0 then
print(self.name .. " defeated!")
else
print(self.name .. ": remaining " .. self.hp .. " HP")
end
end
-- Использование
local hero = Player.new("Geralt", 100)
hero:take_damage(30) -- "Geralt: 70 HP left"
hero:take_damage(80) -- "Geralt is defeated!"Pay attention to colon (:) is a syntactic sugar. hero:take_damage(30) is equivalent to hero.take_damage(hero, 30). The colon automatically passes self.
Chips that surprise
Multiple assignment:
local a, b = 10, 20
a, b = b, a -- swap без временной переменной!
print(a, b) -- 20, 10Ternary through and/or:
-- В Lua нет ternary operator, но есть хак:
local status = (hp > 0) and "alive" or "dead"Varargs — variable number of arguments:
local function sum(...)
local total = 0
for _, v in ipairs({...}) do
total = total + v
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15Where is Lua being used right now?
Lua is not a museum exhibit. It works in production for billions of users:
Roblox — all game scripting on Luau (Lua fork)
Neovim — configs and plugins are written in Lua, not VimScript
Redis — scripts for atomic operations
NGINX/OpenResty — Highly loaded API gateways
World of Warcraft — add-ons written by millions of players
Embedded systems - IoT devices where every kilobyte counts
If you want to consolidate, practice
Theory without practice is forgotten in a week — that's a fact. If you really want to understand programming, and not just read the article and close the tab, try it Code.
Code is an application for learning programming with a focus on practice. Here you don't just read the theory — you solve problems, write code and immediately see the result. Courses in Python, JavaScript, HTML, CSS, and other technologies are designed so that you can learn at your own pace, from your phone or computer.
And we also have Telegram community with 2000+ developers, where useful posts on programming are regularly published. This is a great way to repeat the material in a convenient format — you flip through the feed and at the same time pump up your knowledge. Subscribe and learn with us.
Total
Lua is a language that proves: you don't have to be complex to be powerful. 8 data types, one data structure, minimalist syntax — and it works in game dev, web servers, databases and embedded systems.
If you've ever dreamed of writing a mod for your favorite game, making a plugin for Neovim, or just want to learn a language over the weekend, Lua is a great choice. The entry barrier is minimal, and the opportunities are quite serious.
print("Good luck learning Lua!")