This is a style guide for Roblox's variant of Lua. These guidelines are to keep code consistent across projects, and allow new contributors to learn exactly how to write code for those projects.
This style guide is based off of Olivine Lab's Lua Style Guide.
- Strings
- Functions
- Properties
- Variables
- Classes
- Naming Conventions
- Conditional Expressions & Equality
- Blocks
- Whitespace
-
Use double quotes for strings.
-- bad local name = 'John' -- good local name = "John"
-
Strings longer than 80 characters should be concatenated. Do not use double-brackets (
[[]]
) or backslashes (\
), as line breaks and whitespace will appear in them.-- bad local str = "This is an incredibly long string that exceeds 80 characters and just keeps going. This string has no regard for your well being and will stop at nothing to make your life a living hell." -- bad local str = [[This is an incredibly long string that exceeds 80 characters and just keeps going. This string has no regard for your well being and will stop at nothing to make your life a living hell.]] -- bad local str = "This is an incredibly long string that exceeds 80 characters \ and just keeps going. This string has no regard for your well being and will \ stop at nothing to make your life a living hell." -- good local str = "This is an incredibly long string that exceeds 80 characters ".. "and just keeps going. This string has no regard for your well being and ".. "will stop at nothing to make your life a living hell."
-
Prefer lots of small functions to large, complex functions. Consider reading Small Functions are Good for the Universe.
-
Prefer function syntax over variable syntax.
-- bad local nope = function() -- code end -- good local function yup() -- code end
-
Perform validation early and return as soon as possible.
-- bad local function isGoodName(name) local isGood = #name > 3 isGood = isGood and #name < 30 -- code return isBad end -- good local function isGoodName(name) if #name < 3 or #name > 30 then return false end -- code return true end
-
Prefer defining variables before functions.
-- bad local function foo() -- code end local bar = true local baz = "something" -- good local bar = true local baz = "something" local function foo() -- code end
-
Use dot notation when accessing properties.
local luke = { IsJedi = true, Age = 28 } -- bad local isJedi = luke["IsJedi"] -- good local isJedi = like.IsJedi
-
Use subscript notation (
[]
) when accessing properties with a variable.local luke = { IsJedi = true, Age = 28 } local function getProp(prop) return luke[prop] end local isJedi = getProp("IsJedi")
-
Always use
local
to declare variables.-- bad superPower = SuperPower.new() -- good local superPower = SuperPower.new()
-
Group top-level variables by services, dependencies, constants, and globals. Separate each group by a newline.
-- bad local CONSTANT = true local global = "This can be changed" local runService = game:GetService("RunService") local replicatedStorage = game:GetService("ReplicatedStorage") local module = require(replicatedStorage.ModuleScript) -- good local runService = game:GetService("RunService") local replicatedStorage = game:GetService("ReplicatedStorage") local module = require(replicatedStorage.ModuleScript) local CONSTANT = true local global = "This can be changed"
-
Assign variables at the top of their scope when possible. Scattering them around makes functions hard to parse.
-- bad local function bad() test() print("doing stuff") -- code local name = getName() if name == "test" then return false end return name end -- good local function good() local name = getName() test() print("doing stuff") -- code if name == "test" then return false end return name end
-
All classes must define a
.new()
function for instantiation. This follows Roblox's convention for class constructors.-- bad local gal = Person("Savanna") -- good local gal = Person.new("Savanna")
Roblox commonly uses PascalCase for just about everything. This style guide disagrees with that choice and instead reserves PascalCase for class names and class members.
-
Avoid single letter names. Be descriptive with your naming. You can get away with single-letter names when they are variables in loops.
-- bad local function q() -- code end -- good local function query() -- code end -- good for i=1, #list do -- code end
-
Use underscores for ignored variables.
-- good local _, message = pcall(function() return error("Oops!") end) --good for _, name in pairs(names) do -- code end
-
Use lowerCamelCase when naming objects, functions and instances.
-- bad local not_like_this = {} local OrLikeThis = true --- good local variableWithManyWords = {} local function doThatThing() -- code end
-
Use PascalCase for classes and their members.
-- bad local person = require(replicatedStorage.Person) local guy = person.new("John") local name = guy.name -- good local Person = require(replicatedStorage.Person) local guy = Person.new("John") local name = gui.Name
-
Use CAPITALS_AND_UNDERSCORES for constants.
-- bad local thisWillNeverChange = false -- good local THIS_WILL_NEVER_CHANGE = true
-
When defining services, remove "Service" from the name when possible.
-- bad local contextActionService = game:GetService("ContextActionService") local userInputService = game:GetService("UserInputService") local httpService = game:GetService("HttpService") -- good local contextAction = game:GetService("ContextActionService") local userInput = game:GetService("UserInputService") local http = game:GetService("HttpService")
-
Use
is
orhas
for boolean-returning functions that are part of a class.-- bad local function evil(alignment) return alignment < 100 end -- good local function isEvil(alignment) return alignment < 100 end
-
false
andnil
are falsy in conditional expressions. All else is true.local str = "" if str then -- true end
-
Use shortcuts when you can, unless you need to know the difference between
false
andnil
.-- bad if name ~= nil then -- code end -- good if name then -- code end
-
Prefer
true
statements overfalse
statements where it makes sense. Prioritize truthy conditions when writing multiple conditions.-- bad if not thing then -- code else -- code end -- good if thing then -- code else -- code end
-
Short ternaries are okay.
local function defaultName(name) -- return the default "Waldo" if name is nil return name or "Waldo" end local function brewCoffee(machine) return machine and machine.isLoaded and "coffee brewing" or "fill your water" end
-
Single line blocks are okay for small statements. Try to keep lines to 80 characters. Indent lines if they overflow past the limit.
-- good if test then return false end -- good if test then return false end -- bad if test < 1 and doComplicatedFunction(test) == false or seven == 8 and nine == 10 then doOtherComplicatedFunction() end -- good if test < 1 and doComplicatedFunction(test) == false or seven == 8 and nine == 10 then doOtherComplicatedFunction() return false end
Install EditorConfig for your text editor to have your tabs and other settings configured automatically on a per-project basis.
-
Use soft tabs set to 2 spaces.
-- bad function() ∙∙∙∙local name end -- bad function() ∙local name end -- good function() ∙∙local name end
-
Place 1 space before opening and closing braces. Place no spaces around parenthesis.
-- bad local test = {one=1} -- good local test = { one = 1 } -- bad dog.set("attr",{ Age = "1 year", Breed = "Bernese Mountain Dog" }) -- good dog.set("attr", { Age = "1 year", Breed = "Bernese Mountain Dog" })
-
Place an empty newline at the end of the file.
-- bad (function(global) -- ...stuff... end)(self)
-- good (function(global) -- ...stuff... end)(self)
-
Surround operators with spaces.
-- bad local thing=1 thing = thing-1 thing = thing*1 thing = "string".."s" -- good local thing = 1 thing = thing - 1 thing = thing * 1 thing = "string" .. "s"
-
Use one space after commas.
--bad local thing = {1,2,3} thing = {1 , 2 , 3} thing = {1 ,2 ,3} --good local thing = {1, 2, 3}