luaguides

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

ParameterTypeRequiredDescription
tabletableYesThe table to write to
indexanyYesThe key to set (nil or NaN not allowed)
valueanyYesThe 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 __newindex and 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 __index and __newindex work
  • ref-rawget — read a table value without invoking __index