<!-- fivemad.com, Markdown source of https://fivemad.com/docs/code-optimisation/variables -->
> Source: https://fivemad.com/docs/code-optimisation/variables
> Section: Code optimisation
> Tags: variables, naming, constants, enums, locals, globals, state, lua
> Last updated: 2026-09-25
> Site map for assistants: https://fivemad.com/llms.txt

# Variables, constants and enums

Naming that survives review, where to declare things, why locals beat globals in Lua, and replacing piles of booleans with a single state value.

Naming and placement are not style points. A variable you cannot find the declaration of is a variable you will re-declare somewhere else, and two booleans that describe one thing will eventually disagree.

## Naming

| Kind | Style | Example |
| --- | --- | --- |
| Constant (local or global) | `ALL_CAPS` | `local MAX_DISTANCE = 20.0` |
| Local variable | camelCase | `local shopStock = {}` |
| Resource global | PascalCase | `PlayerData = {}` |
| Unused but required | `_` | `for _, v in pairs(t) do` |

Lua has no `const`, so `ALL_CAPS` is the whole enforcement mechanism. That is fine as long as you are consistent: seeing `MAX_DISTANCE` in the middle of a function tells the reader it was set once at the top of the file and nothing changes it.

Use `_` for values you have to accept and do not use. `for _, shop in pairs(shops)` says "I do not care about the key" without inventing a name like `k` that a reader has to check.

Avoid single letters outside loop counters, and avoid Hungarian style prefixes (`strName`, `bIsDead`). The type is visible from the value and your editor knows it.

## Where to declare

- **File level locals at the top**, grouped, with a blank line under them. Anyone opening the file sees the whole state of it in one screen.
- **Function level locals right before first use**, not at the top of the function. If you have to scroll to see what a name holds, it is declared too far away.
- **Resource globals at the top of the file that owns them**, and only in the file that owns them. A global assigned in three files has no owner and no one can change it safely.

```lua title="client/shops.lua"
local MAX_DISTANCE <const> = 20.0
local INTERACT_KEY <const> = 38  -- E

local shops = {}
local nearestShop = nil
```

CfxLua is Lua 5.4, so `<const>` works and the compiler enforces it: assigning to a `<const>` local is a compile error, not a runtime surprise. When the value is a literal the compiler folds it into the code that uses it, so it costs nothing.

> [!NOTE]
> Lua allows 200 local variables per function and per chunk. Declaring every single config entry as its own file level local is a real way to hit "too many local variables". Group related values into one table instead.

## Locals beat globals

A local lives in a register. A global is a key in the `_ENV` table, so every read and every write is a hash lookup. The difference per access is small, but it is free to avoid:

```lua
-- Three hash lookups per iteration
for i = 1, 1000 do
    Config.total = Config.total + Config.prices[i]
end

-- One lookup each, then registers
local prices = Config.prices
local total = 0
for i = 1, 1000 do
    total = total + prices[i]
end
Config.total = total
```

The same trick works for functions you call in a loop, including globals from the standard library:

```lua
local floor = math.floor
local insert = table.insert   -- when you genuinely need insert
```

Do this inside hot code, not at the top of every file out of habit. A file with 30 hoisted stdlib names at the top is harder to read than the lookups it saves.

## Booleans that should be a state

The pattern to watch for is two or more booleans describing one thing:

```lua title="client.lua (ambiguous)"
local isWalking = false
local isRunning = false
local isSwimming = false
```

Every combination is representable, including the ones that make no sense. What does it mean when `isWalking` and `isSwimming` are both true? What does it mean when all three are false: standing still, or nobody has set them yet? Now every reader of that code has to defend against combinations you never intended, and every writer has to remember to clear the other two.

One value with named options removes the whole problem:

```lua title="client.lua (one state)"
local MOVEMENT <const> = {
    UNKNOWN = 0,
    IDLE = 1,
    WALKING = 2,
    RUNNING = 3,
    SWIMMING = 4,
}

local movement = MOVEMENT.UNKNOWN

local function setMovement(state)
    if movement == state then return end
    movement = state
    TriggerEvent('my_resource:client:movementChanged', state)
end
```

You get an impossible state for free (`UNKNOWN`), adding `CLIMBING` is one line, and comparisons read as English. It also fits state bags and network payloads better: one small number instead of three fields that can arrive out of step. See [State bags and OneSync](/docs/development/state-bags-onesync).

Lua has no real enum type, so the table is the convention. Keep it `<const>`, keep the values numbers if they will be sent over the network, and keep it in a shared file if both sides need it.

## Magic numbers

A number nobody can explain is a bug waiting to be copied:

```lua
TaskPlayAnim(ped, dict, clip, 8.0, -8.0, 3000, 49, 0, false, false, false)
```

`49` is an animation flag set, and the only way to know which is to look it up. Name it:

```lua
local ANIM_FLAGS <const> = 49  -- loop + upper body + allow player control
```

Our [Animation Flags Calculator](/tools/animation-flags-calculator) builds that number from named options, and the [Driving Style Calculator](/tools/driving-style-calculator) does the same for `TaskVehicleDriveToCoord`. Control indexes like `38` have names in the [Controls Reference](/tools/controls-reference).

Next: [Conditionals and early returns](/docs/code-optimisation/conditionals).
