Skip to main content
Lua, despite being a lightweight and flexible language, has several common anti-patterns that can lead to performance issues, maintainability problems, and bugs. Here are the most important anti-patterns to avoid when writing Lua code.
Always use the local keyword when declaring variables. In Lua, variables are global by default, which can lead to unexpected behavior and name collisions.
Organize your code into modules instead of using global functions and variables. This improves maintainability and reduces the risk of name collisions.
Use direct index assignment instead of table.insert() when you know the index in advance. This is more efficient, especially for large tables.
Avoid concatenating strings in loops with the .. operator. Instead, collect strings in a table and use table.concat() at the end, which is much more efficient.
Use proper error handling by checking return values and returning error messages. Lua functions often return nil plus an error message on failure.
Remember that Lua tables are 1-indexed by default. Start your numeric for-loops at 1 when iterating over sequential tables.
Keep variables in the smallest possible scope. Use local variables instead of global ones whenever possible.
Assigning a new empty table to a variable doesn’t clear the original table. Instead, set each key to nil to actually clear a table.
Use metatables to implement object-oriented patterns, operator overloading, and other advanced features in a clean and efficient way.
Use prototype-based OOP with metatables instead of creating new function objects for each instance. This is more memory-efficient and performs better.
Use closures to encapsulate state without exposing it directly. This provides better encapsulation and can be more memory-efficient.
Structure your modules properly by returning a table of functions and values. This prevents polluting the global namespace.
Be careful with upvalues in loops. Create a new local variable inside the loop to capture the current value, not the final value of the loop variable.
Propagate errors up the call stack instead of handling them locally or swallowing them. This allows the caller to decide how to handle errors.
Use pairs() for traversing hash tables and ipairs() for traversing array-like tables. Don’t use the length operator (#) for non-sequential tables.
Document your functions and modules properly. Include parameter descriptions, return values, and usage examples. Consider using a documentation format like LuaDoc or EmmyLua annotations.
Write proper tests for your code using a testing framework like LuaUnit, Busted, or luatest. This makes it easier to verify that your code works as expected and to catch regressions.
Choose appropriate algorithms and data structures for your task. Consider time and space complexity, especially for operations that are performed frequently or with large data sets.
Ensure that resources like files, network connections, and database connections are properly closed, even in error cases or early returns.
Externalize configuration instead of hardcoding values. This makes your code more flexible and easier to deploy in different environments.