# Making sense of variables

**URL:** <https://forum.defold.com/t/making-sense-of-variables/83330>\
**Category:** Questions\
**Created:** [October 7, 2026, 8:26am UTC](https://forum.defold.com/t/making-sense-of-variables/83330 "2026-10-07T08:26:49Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![svalinn85](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/svalinn85/32/44527_2.png) [@svalinn85](https://forum.defold.com/u/svalinn85)\
**Post date:** [October 7, 2026, 8:26am UTC](https://forum.defold.com/t/making-sense-of-variables/83330/1 "2026-10-07T08:26:49Z")

</div>

Having just started with Lua and Defold, coming from other engines like Unity and Godot, one of the first things that really confused me was how Defold and Lua handle variables.

Mainly, I’m referring to the fact that variables often need to be defined in `init()` rather than being organized at the top of a script, as I might be used to from other languages/engines. Then there are concepts like `local`, `self`, and so on.

One thing that really confused me at the beginning was how I seemed to be forced to “separate” variables that are part of the same piece of logic depending on whether I wanted them to be exposed in the editor or kept internal to the script.

For example, let’s say I have:

- `min_speed`

- `max_speed`

- `current_speed`

In another engine, I’d probably want `min_speed` and `max_speed` to be exposed in the editor so I can easily tweak them, while `current_speed` would remain internal to the script since there’s no real benefit in exposing it.

If I understand correctly, in Defold I could achieve this by using `go.property()` for the first two, while defining the third as a `self` variable in `init()`.

However, the idea of having to “split” these three variables between the top of the script and `init()`, even though they are all part of the same logic, feels a little strange to me.

So I kept researching and experimenting, and I ended up wondering whether a structure like this might make sense.

Using the same example, something along these lines:

```lua
go.property("min_speed", 0)
go.property("max_speed", 100)

function init(self)
    self.speed_stats = {
        min = self.min_speed,
        max = self.max_speed,
        cur = 50
    }
end

function whatever(self)
    local speed = self.speed_stats

    speed.min = whatever
    speed.max = whatever
    speed.cur = whatever
end

```

This way, all the speed-related variables are grouped together, while `max_speed` can still be exposed in the editor.

I also like that, inside other functions, I can do:

```lua
local speed = self.speed_stats

```

and then work with `speed.min`, `speed.max`, etc., rather than having to repeatedly write `self.variable`.

So I’m wondering: **is this a reasonable/idiomatic way to structure variables in Defold?** Is this something commonly done, or would there be a better approach that I’m missing?

I’m still getting used to the way Defold/Lua handles state and variables, so I’d really appreciate some insight into how more experienced Defold developers usually approach this.

Thanks for helping out! 😊

---

<div class="post-metadata">

**Author:** ![Pawel](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/pawel/32/24623_2.png) [@Pawel](https://forum.defold.com/u/Pawel)\
**Post date:** [October 7, 2026, 9:10am UTC](https://forum.defold.com/t/making-sense-of-variables/83330/2 "2026-10-07T09:10:41Z")

</div>

I think the easiest way to understand variables in Defold is to stop thinking about where they are written in the file, and instead think about **who** should own the value and how long it should live.

There are basically a few common cases:

### `local` inside a function

Use this for temporary values that are only needed while that function is running.

```lua
function update(self, dt)
    local distance = self.speed * dt
    local position = go.get_position()

    position.x = position.x + distance
    go.set_position(position)
end

```

If `distance` and `position` don’t need to exist after `update()`, there is no reason to put them in `self`, so you can make them local to the scope. On the other hand `speed` might be adjusted in e.g. on\_input, so it’s convenient to put it in `self`, and it’s available for all the Defold lifecycle functions in the script (and other functions that take `self` table as parameter - as it’s a simple Lua table like any other).

As a rule of thumb: prefer `local` unless the value needs to be available between function calls.

* * *

### Top-level `local`

This one is important because it behaves differently from `self` (explained below). This is also sometimes a good optimization for variables used many times in huge loops in functions (rarely a really important for performance case, unless you’re making **really** huge loops) - in the above example we could declare local `distance` or `position` outside the `update()`:

```lua
local distance = 0
local position
function update(self, dt)
    distance = self.speed * dt
    position = go.get_position()

    position.x = position.x + distance
    go.set_position(position)
end

```

so it doesn’t need to be created every time `update()` is called. But this also changes the scope of this variables. These are now available and could be modified in any other function in the script!

Moreover, it is **shared by all instances using that script file**!

This means, if you use the same script for two instances, e.g. two enemies - they will be overriding each other’s `distance`, which might cause unexpected behaviours. We say such a variable has a mutable state.

So this can be great for things that are effectively constants:

```lua
local MAX_ACCELERATION = 20
local MSG_DAMAGE = hash("damage")
local UP = vmath.vector3(0, 1, 0)

```

or for… helper functions (because functions can be assigned to variables in Lua in the same way as numbers or strings):

```lua
local function clamp_speed(speed, min_speed, max_speed)
    return math.max(min_speed, math.min(speed, max_speed))
end

```

So if you want to have a variable that is only bound to a certain **instance** of the script (e.g. for per-enemy health, distance, etc) you want:

```lua
self.current_health = 100

```

* * *

### `self.something`

Use `self` for state **belonging** to this particular script **instance**.

For example:

```lua
function init(self)
    self.current_speed = 50
    self.is_moving = false
end

function update(self, dt)
    if self.is_moving then
        self.current_speed = self.current_speed + dt
    end
end

```

`current_speed` should be available and persistent from one frame to the next, so it should be in `self`.

Each instance using this script gets its own value.

So if you have 20 enemies using the same script:

```lua
self.health

```

means each enemy can have different health.

This is probably the closest equivalent to what you might think of as an instance/member variable in C#, GDScript, etc.

* * *

### `go.property()`

I would think of these more as **configuration** for the script instance.

For example:

```lua
go.property("min_speed", 0)
go.property("max_speed", 100)

```

Defold then exposes these in the editor, lets you set different values on different instances, pass them when spawning objects from factories, access them externally, etc.

You noticed correctly all properties are then available in the `self` table, so they share the same characteristics as `self` variables described above - they are belonging to the **instance** of the script.  
Inside the script they ca be accessed through `self`:

```lua
print(self.min_speed)
print(self.max_speed)

```

The fact that `go.property()` has to be used outside `init()` (or any other function) is only just because of how Defold declares these properties. I wouldn’t worry too much about the visual separation in the file, but it’s good to just put them always at the top of the script.

* * *

### Globals

Something like:

```lua
current_speed = 50

```

without `local` or `self` creates a **global** variable. This means this variable is available not only in this script, but also in any other scripts. So if you declare a global in `hero.script` it will also be available in `enemy.script`.

I would generally avoid that. Globals are available much more widely than you probably intend and make it very easy for unrelated code to accidentally depend on or modify them. You might think it’s good for having them for constants that are really contants, immutable and it would be ok, but it’s always better to control the scope - why having a variable in memory that no script needs at the moment?

If you genuinely need shared game state, I would usually make that explicit with a Lua module rather than relying on globals. It’s better to put constants in separate Lua modules and require them where needed.

* * *

For your particular example, I would probably just write something like:

```lua
go.property("min_speed", 0)
go.property("max_speed", 100)

function init(self)
    self.current_speed = 50
end

```

and then:

```lua
function whatever(self)
    self.current_speed = math.max(
        self.min_speed,
        math.min(self.current_speed, self.max_speed)
    )
end

```

That might look slightly less “grouped” than:

```lua
self.speed_stats = {
    min = self.min_speed,
    max = self.max_speed,
    cur = 50
}

```

but there is an important difference.

With your version:

```lua
self.speed_stats.min = self.min_speed

```

you are **copying the value**.

After that these are two independent values:

```lua
self.min_speed
self.speed_stats.min

```

Changing one will not automatically change the other. That creates two potential “sources of truth”, which can become confusing later. If you really like grouping related runtime state, that’s completely reasonable:

```lua
function init(self)
    self.speed = {
        current = 50,
        acceleration = 0
    }
end

```

and keeping configuration as properties:

```lua
go.property("min_speed", 0)
go.property("max_speed", 100)

```

Then the distinction is actually quite useful:

```lua
self.min_speed -- configuration
self.max_speed -- configuration

self.speed.current -- runtime state
self.speed.acceleration

```

Personally, though, for only one or two values I wouldn’t create a table just for grouping. `self.current_speed` is perfectly normal, regular Defold code 😃

Beside `go.properties` specific to Defold, all this is really only Lua 😉

---

<div class="post-metadata">

**Author:** ![svalinn85](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/svalinn85/32/44527_2.png) [@svalinn85](https://forum.defold.com/u/svalinn85)\
**Post date:** [October 7, 2026, 10:38am UTC](https://forum.defold.com/t/making-sense-of-variables/83330/3 "2026-10-07T10:38:01Z")

</div>

Yes, I think I have a basic understanding of how `local` and `self` work.

That said, I still find the way variables can end up being spread throughout a Defold script, with different variables being declared in different functions, quite messy and… unpleasant, at least for my brain. 😅

For example, I imagine having a very long script with a lot of functions, and each function has its own local variables. If I ever need to find a specific variable, I might have to go through the entire script, function by function, looking at all the variables declared in each one, unless I remember exactly where it is.

That’s why it is quite important for me to have some kind of clearly identifiable section where I can see the variables/state of a particular system in one place. It makes the code much easier for me to scan and understand later.

That’s actually why I spent way too much time on this yesterday… I was up until 4 AM reading about Lua/Defold variables and experimenting with different ways of structuring them. 😅

And I think this is also where I may not have explained my original question very well.

What I was specifically trying to achieve was to keep **all the variables belonging to the same piece of logic together** , even when some of them are exposed as `go.property()` and others are internal runtime state.

So, using the same example, I was thinking about something like:

```lua
go.property("min_speed", 0)
go.property("max_speed", 100)

function init(self)
    self.speed = {
        min = self.min_speed,
        max = self.max_speed,
        current = 50
    }
end

```

The idea is that `min`, `max`, and `current` are conceptually all part of the same `speed` state, so I would then use:

```lua
self.speed.min
self.speed.max
self.speed.current

```

throughout the rest of the script.

And then, inside a function where I’m working extensively with that state, I would simply do:

```lua
function whatever(self)
    local speed = self.speed

    speed.min = ...
    speed.max = ...
    speed.current = ...
end

```

So I’m actually asking about **both** of these things:

1. Is it reasonable to group related state into a table like `self.speed`, even if `min` and `max` initially come from `go.property()`?

2. Is it also reasonable/common practice to create a local reference such as `local speed = self.speed` inside a function, so I don’t have to repeatedly write `self.speed.current`, `self.speed.min`, etc.?

3. , as a “bonus” question: are there any issues that would be created, in the short/long run by this approach?

I understand your point that:

```lua
self.speed.max = self.max_speed

```

creates a copy, meaning `self.speed.max` and `self.max_speed` become two separate values. My intention would be that the `go.property()` values are only used to initialize the runtime table, and then `self.speed` becomes the actual runtime state that I work with.

So the main thing I’m trying to figure out is whether this overall approach is considered reasonable/idiomatic in Defold, or whether I’m introducing some kind of problem or bad practice by doing it this way.

I’m not really trying to avoid typing `self` just for the sake of avoiding a few characters. It’s more about **organization** : I want related state to live together, and then I want to be able to locally reference that state when working with it inside a particular function.

Thanks for explaining the fundamentals of variables in Defold, that definitely helped. I’m just still trying to get an answer to the specific organizational approach I’m proposing. 😄

---

<div class="post-metadata">

**Author:** ![Mathias](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/mathias/32/44015_2.png) [@Mathias](https://forum.defold.com/u/Mathias)\
**Post date:** [October 7, 2026, 4:08pm UTC](https://forum.defold.com/t/making-sense-of-variables/83330/4 "2026-10-07T16:08:52Z")

</div>

Doing what you propose is totally fine.  
Instancing a local variable to shorten variable lookup path is handy and usefull, it even speed up the lookup of values since there is less tables to lookup.

For go.property() you should just be aware that they can be animated via go.animate(), this can be handy for example for a color property or a things like that. So if you copy its value, you wont have this live-link, so you’ll have somewhere (in the update for ex.) reset self.speed.current\_speed = self.animated\_speed to synchronize things.

Personnally I dont use these much, for me go.property() is just an interface for the editor and for factories. This point is crucial tho:  
If you want to be able to configure your instance at object creation with factories, you have to set them as go.property().  
Another way is to not use that, but use a message to configure the object, like:

```lua

function on_message(self, message_id, message)
 If message_id == hash('configure') then 
    Self.speed = message.min_speed
End
End 

```

Then when spawning the object, you

```lua
Local id = factory.create(my_object_factory)
msg.post(id, hash('configure'), {min_speed=100})

```

I tend to write only lua modules, like player.lua, then the player.script is just the glue to wire script init/update/message etc. functions and go.properties() to my module.  
So I consider go.properties() as arguments to my module instance construtor.

Like this everything is lua first code, and you can grow your code base without linking it to .script.  
For example you can have only one enemies\_manager.script that just require a bunch of lua modules for all enemies prefabs, a generic enemy.go and enemy.script, and just spawn and configure.

---

<div class="post-metadata">

**Author:** ![svalinn85](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/svalinn85/32/44527_2.png) [@svalinn85](https://forum.defold.com/u/svalinn85)\
**Post date:** [October 7, 2026, 4:55pm UTC](https://forum.defold.com/t/making-sense-of-variables/83330/5 "2026-10-07T16:55:57Z")

</div>

Hey, thank you for jumping in!

That’s actually very helpful, especially knowing that the approach I was thinking about is totally fine. The part about creating a local reference to shorten the lookup path is exactly what I was getting at with `local speed = self.speed`. 😊

I still haven’t gone as far as understanding what you mean when you talk about messages and modules, though. I’m really a total beginner with Lua and Defold right now. 😅

I do know that Defold uses messages to let different elements communicate with each other, but I haven’t reached the point where I can really make sense of how and when I should use them. Same thing with Lua modules: that’s probably a bit further down the rabbit hole for me. 😄

The `go.animate()` part is really interesting, though! I hadn’t considered that a `go.property()` could be animated and that copying its value into another table would break that live connection. That’s definitely something I’ll keep in mind.

For now, I think I’ll stick to the simpler approach and experiment with the concepts one at a time. There’s already quite a lot to digest coming from Unity/Godot. 😂

Thanks again for the explanation!

---

<div class="post-metadata">

**Author:** ![Mathias](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/mathias/32/44015_2.png) [@Mathias](https://forum.defold.com/u/Mathias)\
**Post date:** [October 7, 2026, 6:44pm UTC](https://forum.defold.com/t/making-sense-of-variables/83330/6 "2026-10-07T18:44:48Z")

</div>

You’re welcome!  
As for the module part, you can absolutely start with creating a game object and an associated small .script for everyone of your objects/prefabs, and just use them as is in your collections. This is actually even a better idea to start this way as everything is simple and statically defined in your project, it will be easyer to think about your project this ways.  
I recommand you to create a folder for each type of object you create, with everything inside (gameobject, script) so things are organised functionaly and you find things back. A good way to find stuff is also just ctrl+O (ctrl+p in vscode) and type name of file to open it.  
Or ctl+shift+f to just search into files.

One last thing:  
I strongly recommand to get used to Lua ANNOTATIONS quickly, and defines them early for your objects, as it really helps to avoid dumb errors or typos. It provides also autocomplete for fields.

See [Lua Language Server | Wiki](https://luals.github.io/wiki/annotations/)

What I do even in small scripts is to annotate a class at start of script with name MyscriptData and add all fields that should be in the self object:

```lua
-- player.script

---@class PlayerData
---@field health number 
---@field current_speed number current speed 
---@field velocity vector3 velocity vector
---@field sprite url url to the sprite component

---@param PlayerData
local function my_helper(self)
  --self will auto complete
end

---@param self PlayerData
function init(self)
  self.health = 100
 Self.current_speed = 10
  self.velocity = vmath.vector3(1,0,0) * self.current_speed
  self.sprite = msg.url('#sprite')
end

---@param self PlayerData
---@param dt number
function update(self, dt)
 -- here self will autocomplete
my_helper(self)
end

```

You’ll get linter and lua check information in the “Problem” console when building, or live in VSCode for example
