Skip to the content.

Welcome to Lua

Lua logo

This is a beginner-friendly guide to the Lua programming language. This guide is intended for people that are completely new to programming as well as folks that already might have experience with other programming languages (such as Python, JavaScript, or C#).

I wasn’t able to find a written and easy-to-understand tutorial anywhere else, so I’ve gathered all of the most fundamental concepts here in the case it might be useful to you as well.

Introduction to Lua

Lua is a fast, simple, and portable programming language best (and most commonly) used for video games, embedded devices, and as modular libraries in other programs.

Pros

Cons

What can I do with Lua?

Lua is quite a versatile programming language. But, it’s mostly best at things like:

Use Case Description Examples
Embedded programming Writing code to run on IoT or small computing devices Raspberry Pi
Video game programming Writing video game logic ROBLOX, PICO-8, LOVE2D, Defold
Network programming Writing fast and small programs for computer networking CISCO Systems, nmap, Kong API Gateway, ModSecurity
Cross-language libraries Writing flexible and interoperable libraries that can work with multiple programming languages NLua (.NET / C#)
Complex config files Writing configuration files that require lots of complexity and advanced features Neovim config

How to get started programming with Lua

For programming, you will need to use a code editor application to create your code, as well as have the interpreter for your computer to know how to run Lua code.

The easiest way to get started without installing anything is to use an in-browser editor, such as Replit.

Or, if you would like to run things locally on your computer you will need:

Note: If you do run into any issues during this tutorial or while installing the pre-requisite software, try typing your exact question into a search engine like Google or DuckDuckGo and see what comes up!

Troubleshooting issues by looking up information online is one of the main portions of time spent computer programming; there’s no sense wracking your brain to try and remember something specific when a refresher is usually just a moderately-crafted Google search away. It’s a great skill to build up as it’s useful for finding out things you don’t know or things that you’ve just forgotten over time!

1 - Data Types

There are 5 fundamental types of data in Lua:

Type Example Description
string Hello Text
number 123 Contains either an integer or a decimal number, as well as positive or negative signs
boolean false True or False
nil nil The absence of a value, often known as null in other languages
table {key1 = value1, key2 = value2, ...}
or {value1, value2, ...}
Contains a collection of related values, accessible by their key or by their position in the list

A variable in computer programming is used to store information inside a computer program. Each value that you can give to a variable has a data type, which is a term that describes what type of data is stored into a variable.

Lua is a dynamically typed programming language, meaning you don’t need to explicitly say what type of data a variable should contain and the Lua interpreter will figure out the type for you.

Strings

Strings are used when you want to represent text. Text data is generally used when you want to represent a more abstract form of information intended for humans to read.

In the below example, the print() function outputs the result to the console.

-- Declares a variable `message` with a string
message = "Hello"

print(message) --> 'Hello'

Sometimes, there’s a need to get fancy with your strings. If you would like to insert another value inside a string, you would use string interpolation. In Lua, that is done with two periods: ..

name = "Bob"
message = "Hello, "..name.."!"

print(message) --> 'Hello, Bob!'

Numbers

Numbers are used by computer programs to estimate something that has a numerical value to it. This can be used for doing something in the code X number of times, describing an amount of money, a pixel width/position of something on the screen, etc;

The below example draws a filled circle onto the screen in the PICO-8 game engine.

x = 64
y = 64
radius = 32
color = 8 -- 8 represents `red` in PICO-8's color pallette

circfill(x, y, radius, color)

Booleans

Booleans are simply a type that shows either a true or a false. These types are heavily relied on for conditional statements in program logic, meaning things that should happen only if something else is true or false.

In the below example, since the variable shouldPrintMessage is set to false, the result will not print.

shouldPrintMessage = false 

if shouldPrintMessage == true then
    print("Mitochondria is the powerhouse of the cell.")
end

Nil

The value type nil is an empty value that occurs when the program attempts to access something that does not exist. Typically, it’s something you want to avoid since having a something with nothing in it isn’t very useful.

In the below example, the print() function is attempting to print the value of a variable that hasn’t been created yet. So, it will be empty and contain a nil.

print(notARealVariable) --> nil

Tables

Tables are used to store collections of related data. Collecting data into a singular entity makes it significantly easier to organize as well as perform tasks on such as creating, reading, updating, or deleting data.

In Lua, Tables are the only data collection type, and are quite flexible in their usage.

In the below example, the first item in the table list is printed to the console. Notably, Lua starts indexes at 1 instead of 0 like most other languages.

snacks = { "Fruit", "Popcorn", "Chocolate Cake" }

-- Adding a new item to the list
table.insert(snacks, "Brotwurst")

-- Reading an item from the list
print(snacks[1])

-- Updating an item in the list
snacks[4] = "Potato Chips"

-- Removing the third item from the list
table.remove(snacks, 3)

You can also create key-value pairs in tables. Key-value pairs are used for when it would be useful to have self-describing data.

superman = {
    firstName = "Clark",
    lastName = "Kent",
    age = 25,
    canFly = true,
    allergies = { "Kryptonite" }
}

print(superman.firstName) --> Clark
print(superman.canFly) --> true

2 - Operators

Operators are symbols that represent a type of action between two or more things. This can be something like comparing two values, doing arithmetic operations on them, or control flow.

Arithmetic

Lua’s arithmetic operators follow the standard set found in most other programming languages:

Operation Symbol
Add +
Subtract -
Multiply *
Divide /
Exponents ^
Remainder (Modulo) %
a = 50
b = 4

-- Addition
print(a + b) --> 54

-- Subtraction
print(a - b) --> 46

-- Multiplication
print(a * b) --> 200

-- Division
print(a / b) --> 12.5

-- Exponents
print(a^b) --> 6250000.0

-- Remainder (Modulo)
-- The 'Modulo' operator divides the two numbers, then outputs the remainder
print(a % b) --> 2

Relational

A common thing to do in computer programs is compare two values. This can be something like checking if two values are equal, or if numerical values are greater or less than one another.

Equator Symbol
Equal to ==
Not equal to ~=
Greater than >
Greater than or equal to >=
Less than <
Less than or equal to <=
-- Equal to
print(3 == 5) --> false

-- Not equal to
print(3 ~= 5) --> true

-- Greater than
print(3 > 5) --> false

-- Greater than or equal to
print(3 >= 3) --> true

-- Less than
print(3 < 5) --> false

-- Less than or equal to
print(3 <= 5) --> true

Each of the other data types are frequently compared as well using the equal to (==) and not equal to (~=) operators.

name = "James"
isCool = true

print(name == "James") --> true
print(isCool == true) --> true
print(newVariable ~= nil) --> false

Lexical - Comparisons

The word lexical means something that relates to the vocabulary of a language. In the case of programming, it typically refers to a written word that has a meaning in the program.

The following words function as operators in Lua:

The and operator checks if both conditions are true. If they are, it returns the appropriate result.

name = "James"
isCool = true

print(name == "James" and isCool == false) --> false

Conversely, if you would like to check if either one of the conditions is true, you would use or:

name = "James"
isCool = true

print(name == "James" or isCool == false) --> true

When you would like to check for the opposite of a boolean result, you would use the not operator.

isCool = true

print(not isCool) --> false

3 - Conditionals

Sometimes you would only like to execute certain logic in certain cases. To do this, you would use a conditional statement like if.

a = 3
b = 4

if (a < b) then
    print("a is less than b!")
end

But what if you wanted to print something in the cases where a was greater than or equal to b? In that case, you would use an else.

a = 3
b = 4

if (a < b) then
    print("a is less than b!")
else
    print("a is greater than or equal to b!")
end

Now, let’s say you wanted to know exactly when the two values were equal. To do that, you would add an elseif in the middle.

a = 3
b = 4

if (a < b) then
    print("a is less than b!")
elseif (a == b)
    print("a is equal to b!")
else
    print("a is greater than b!")
end

4 - Loops

When you’d like to run the same chunk of code repeatedly, you would use a loop block.

There’s a few different flavors each with their own use cases.

For (Numeric)

When you know the exact number of times to do something repeatedly, you would use a numeric for loop.

for i = 1, 10 do
    print("This loop has run "..i.." times!")
end

For loops in Lua consist of a few parts, each separated by a comma (,).

  1. The first argument (usually named i, short-form for index) is a variable that represents the number that the loop starts from.
  2. The second argument is the end number that the loop index should be able to reach. When the loop index i is about to pass this number, the loop stops and the code moves on to the next statement after the loop.
  3. (Optional) There is also an optional third argument that represents a number to be added to the index before each time the loop should repeat. By default, the loop adds 1 to the index.

Here is an example with the third argument included:

-- Increments by 2 each iteration
for i = 1, 10, 2 do
    print("The index is: "..i)
end

-- Increments by -1 (subtracts) each iteration
for i = 10, 1, -1 do
    print("The index is: "..i)
end

Notice that in the second example with subtraction, the loop has to start from a higher number and count down to the lower number.

For (Generic)

When you would like to loop over elements in a table, you could use a generic for loop.

Generic loops can be used for tables that have named keys

{ key1 = value1, key2 = value2, ... }

as well as when a table does not have named keys

{ value1, value2, ...}

Because of this, Lua provides two (virtually identical) functions. Each of these is optimized for those use cases:

When a table does not contain named keys and just contains values, the key value is just the index in the table (e.g. 1, 2, 3).

snacks = { "Fruit", "Popcorn", "Chocolate Cake" }

for index, value in ipairs(snacks) do
    print(index, value)
end

-- The above outputs:
--  1       Fruit
--  2       Popcorn
--  3       Chocolate Cake

You also don’t technically need to write out the first argument if you don’t plan on using the index. A common code convention is to use an underscore (_) known as a discard variable.

snacks = { "Fruit", "Popcorn", "Chocolate Cake" }

for _, value in ipairs(snacks) do
    print(value)
end

-- The above outputs:
--  Fruit
--  Popcorn
--  Chocolate Cake

To loop over a table that contains keys, you would do so in the same way, but just using the pairs() function instead:

superman = {
    firstName = "Clark",
    lastName = "Kent",
    age = 25,
    canFly = true,
    allergies = { "Kryptonite" }
}

for key, value in pairs(superman) do
    print(key, value)
end

-- The above outputs:
--  canFly          true
--  lastName        Kent
--  allergies       table: 0x55b668f326b0
--  firstName       Clark
--  age             25

Repeat Until

The repeat until loop is used when you would like to do something over and over until a condition is true.

Remember: If your condition never becomes false, your code will run in an infinite loop. So, make sure that your condition will eventually return true.

The key difference between this and a while loop is what happens on their first round.

A very common use case for these type of loops is to check user input, where you would like to only proceed once you’ve verified the user has typed in the correct thing.

print("What is 2 + 2?")
answer = "4"

repeat
    input = io.read() -- Read the user's keyboard input
    if input ~= answer then
        print("Wrong answer, try again!")
    end
until input == answer

print("Congrats, that's right!")

The above example will ask the user to keep guessing until they guess the number 4 into the console input.

Hey but wait a minute, in this game it repeats forever until they guess the correct number. What if we wanted to let the user manually exit the program?

To do that, we would use the break keyword, which allows breaking out of a loop.

In the below example, if the user types in “quit”, the break statement will exit out of the loop it is in and not prompt the user for another answer.

print("What is 30 + 12?")
answer = "42"

print("(Type 'quit' to exit if this is too hard)")

repeat
    input = io.read() -- Read the user's keyboard input
    if input == "quit" then 
        break -- Exits out of the `repeat until` loop
    elseif input ~= answer then
        print("Wrong answer, try again!")
    else
        print("Congrats, that's right!")
    end
until input == answer

Syntactically, the repeat until loop is Lua’s named flavor of the do while loop commonly found in other programming languages.

While

While loops are used when you would like to do something over and over until a condition is true, but check the condition first before running it for the first time.

The key difference between this and a repeat until loop is what happens on their first round.

colors = {}
print("What are your two favorite colors?")

-- Note: `#` in `#colors` is for the length of a table with non-named keys.
while #colors < 2 do
    print("Colors entered: "..#colors)
    input = io.read()
    table.insert(colors, input)
end

print(colors[1].." and "..colors[2].." are awesome! I wonder what they would look like together.")

5 - Functions

Functions are used when you would like to re-use the same chunk of code in more than one place. This helps keep code readable and easier to manage.

Functions can have two parts, an input and an output. Depending on what type of logic you have, you may have either none of these, both of these, or just one of the two.

To output something from a function, you would use the return keyword, followed by the one or more values you would like to return. After it gets returned, it is passed back to whichever line of code called the function.

Both Input + Output

function sum(number1, number2)
    return number1 + number2
end

print(sum(3, 3))
print(sum(33, 26))
print(sum(335, 834))

In the above example, the sum() function takes two numbers to add as parameters, then outputs the sum as a result. The result then is passed to print(), which then prints it to the console.

Neither

function printCurrentTime()
    print(os.date())
end

printCurrentTime()

In the above example, the printCurrentTime() function prints the computer’s date and time to the console.

Only Input

function printGreeting(name)
    print("Hello there, "..name.."!")
end

printGreeting("John")
printGreeting("Mervis")

In the above example, the printGreeting() function takes a name and prints a greeting message to the console.

Only Output

function getDayOfWeek()
    return os.date("%A")
end

dayOfWeek = getDayOfWeek()

if dayOfWeek == "Wednesday" then
    print("It is Wednesday, my dudes.")
    print("AAAAAAAAAAAAAAAAAAAAAAAAA")
else 
    print("Today is "..dayOfWeek)
end

Alternative Function Syntax

If your function happens to take a singular string as a parameter, you can also omit the parenthesis () and call your function like this:

function printGreeting(name)
    print("Hello there, "..name.."!")
end

printGreeting "John" --> Hello there, John!
printGreeting "Mervis" --> Hello there, Mervis!

6 - Scoping

In simple programs like the examples mentioned previously, limiting the access of which variables/functions can see other variables/functions is not too important, as most of the program executes within the same scope.

But, as your project grows in complexity with more features and starts branching to multiple files, it becomes drastically more important to make sure that you limit things from accessing things it should probably not need to.

This prevents quite a bit of headache when debugging, as you can more easily track where your functions are being called, as well as where each of your variables are being set / read from.

There are two types of scope in Lua, global scope and local scope.

A good rule of thumb is just to create everything under local scope, and then when you specifically have a use case for using global values you would create those as necessary.

To locally scope your variables/functions, you would use the local keyword.

local names = {
    "Jimmy",
    "Johnny",
    "Fred"
}

local function printInUpperCase(text)
    local upperCaseName = string.upper(text)
    print(upperCaseName)
end

printInUpperCase("Hello friends:")

for _, value in ipairs(names) do
    printInUpperCase(value)
end

Note: Since function and loop parameters would always be local, you do not need to explicitly state those as local as the Lua interpreter will do that for you.

End Note

Here are a few pieces of general programming advice that hopefully can be helpful in your journey not just with Lua, but with software development in general:

All in all, hopefully the concepts in this guide have helped you understand the syntax of the language, as well as learn how to create great computer programs with Lua!

Note: If you notice anything missing or something that can be improved, feel free to fork this repo and submit a pull request on GitHub!

If you’d like to learn more, be sure to check out the Lua documentation or one of the more advanced learning articles here: