rawset
rawset(table, index, value) rawset writes a value into a table while skipping any __newindex metamethod. When you need to store something in a table without triggering custom write behavior, this is the function to use.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
table | table | Yes | The table to write to |
index | any | Yes | The key to set (nil or NaN not allowed) |
value | any | Yes | The value to store |
rawset returns table — the first argument. This lets you chain calls together.
How It Differs From Bracket Assignment
When you assign to a table with bracket notation or dot notation, Lua checks whether the table has a metatable with a __newindex metamethod. If it does, Lua calls that metamethod instead of performing a direct write. rawset skips this entirely.
local t = setmetatable({}, {
__newindex = function()
error("writing to this table is not allowed")
end
})
-- t.some_key = "value" -- would raise an error via __newindex
rawset(t, "some_key", "value")
print(t.some_key) -- "value"
Preventing Infinite Recursion in __newindex
When you implement a custom __newindex that wraps an underlying table, calling rawset to write to that inner table prevents __newindex from firing again and causing infinite recursion.
local storage = {}
local proxy = setmetatable({}, {
__newindex = function(self, k, v)
rawset(storage, k, v) -- write without re-triggering __newindex
end,
__index = function(self, k)
return rawget(storage, k)
end
})
proxy.name = "alice"
proxy.age = 30
print(proxy.name) -- "alice"
print(proxy.age) -- 30
Without rawset, the __newindex function would try to assign to storage, which has no metatable, but the call to rawset is what prevents the metamethod from firing on proxy in the first place. The infinite recursion risk comes from assigning directly to proxy inside __newindex.
Chaining Calls
Since rawset returns the table, you can build up a table in one expression:
local t = {}
rawset(rawset(rawset(t, "a", 1), "b", 2), "c", 3)
print(t.a, t.b, t.c) -- 1 2 3
Or more readably, in sequence:
local t = {}
rawset(t, "name", "bob")
rawset(t, "active", true)
rawset(t, "score", 42)
Deleting a Key by Setting It to nil
You can remove a key from a table’s raw storage by setting it to nil:
local t = {x = 10, y = 20, z = 30}
rawset(t, "y", nil) -- removes the "y" key entirely
print(t.y) -- nil
print(t.z) -- 30
Note that setting a key to nil is different from the key not existing at all — both return nil when read. But rawset with nil removes the key from the table’s own storage, so it no longer shows up in pairs iteration.
Error Cases
rawset validates its arguments strictly:
rawset({}, nil, "value")
-- stdin:1: bad argument #2 to 'rawset' (value expected)
rawset({}, 0/0, "value")
-- stdin:1: bad argument #2 to 'rawset' (value expected)
rawset("not a table", "k", "v")
-- stdin:1: bad argument #1 to 'rawset' (table expected)
Unlike bracket assignment, which silently ignores attempts to use nil as a key, rawset raises an error. NaN also cannot be used as an index.
When to Use rawset
You reach for rawset when:
- You are implementing a custom
__newindexand need to write the actual value without triggering the metamethod again - You want to store values in a table that has a restrictive
__newindex(e.g., a read-only proxy) - You are building a table manually in a tight loop and want to avoid any metatable overhead
For reading from tables without __index, use rawget.
See Also
- next — iterate raw table keys without triggering metamethods
- lua-metatables — learn how
__indexand__newindexwork - ref-rawget — read a table value without invoking
__index