luaguides

next

next(table, index)

next() is the low-level function that underlies Lua’s table iteration. It returns the next key-value pair after a given position, or nil when there are no more entries. Understanding next directly helps you grasp how pairs() works and when you need manual control over traversal.

Signature

next(table, index)
ParameterTypeDefaultDescription
tabletableThe table to traverse.
indexanynilThe current key position. Pass nil to start traversal from the beginning.

Return values:

  • If more elements exist: (next_key, next_value)
  • If at the end or table is empty: nil

Basic Traversal

When you call next with nil as the index, it returns the first key-value pair:

local t = {name = "Alice", age = 30, city = "London"}
local k, v = next(t, nil)
print(k, v)  -- e.g., "name\tAlice" (order varies)

To continue traversal, pass the key returned by the previous call back into next:

local t = {a = 1, b = 2, c = 3}
local k, v = next(t, nil)
while k ~= nil do
    print(k, v)
    k, v = next(t, k)
end

This manual iteration pattern is equivalent to what pairs() does internally. In fact, pairs(t) is defined as the expression next, t, nil — an iterator function, table, and starting state bundled together.

Checking for Empty Tables

next(t) returns nil when called on an empty table, making it a clean way to test for emptiness:

local empty = {}
local full = {a = 1}

if next(empty) == nil then
    print("table is empty")       -- prints
end

if next(full) ~= nil then
    print("table has entries")   -- prints
end

This is the idiomatic Lua pattern. A common helper:

function is_empty(t)
    return next(t) == nil
end

Why Traversal Order Is Unspecified

next walks the hash part of a table, and the order depends on how keys are arranged in hash buckets. This order has no relation to insertion order or numeric magnitude:

local t = {z = 1, a = 2, m = 3}
for k, v in next, t, nil do
    print(k, v)
end
-- Output order is unpredictable — not alphabetical, not insertion order

If you need numeric keys in sorted order, use ipairs() with table.sort() on the keys, or build an explicit numeric loop.

Sparse Tables

next visits every key present in a sparse table, regardless of gaps:

local sparse = {}
sparse[1] = "first"
sparse[100] = "hundredth"
sparse[50] = "fiftieth"

local k, v = next(sparse, nil)
while k ~= nil do
    print(k, v)
    k, v = next(sparse, k)
end
-- Visits all three entries (order undefined)
-- 1     first
-- 50    fiftieth
-- 100   hundredth

ipairs() would stop at the first gap in numeric keys. next handles sparse tables faithfully.

Modifying a Table During Iteration

This is the most important gotcha: never assign to a non-existent key while iterating. Doing so invalidates the traversal state and can cause infinite loops or skipped entries.

You can safely modify or delete existing keys during iteration:

local t = {a = 1, b = 2, c = 3}

for k, v in next, t, nil do
    if k == "b" then
        t[k] = nil  -- safe: deleting existing key
    end
end
-- t is now {a = 1, c = 3}

But adding a new key mid-iteration is dangerous:

local t = {a = 1, b = 2}

for k, v in next, t, nil do
    t.z = 99  -- unsafe: modifies table during traversal
    print(k, v)
end
-- May print extra entries, loop infinitely, or behave unpredictably

For safe bulk modification, collect keys first, then modify:

local keys = {}
for k in pairs(t) do keys[#keys + 1] = k end

for _, k in ipairs(keys) do
    if condition then t[k] = nil end
end

Relationship to pairs()

pairs(t) is syntactic sugar for next, t, nil. This means:

for k, v in pairs(t) do ... end

is exactly equivalent to:

for k, v in next, t, nil do ... end

Understanding this lets you write custom iteration patterns. For example, skipping a specific key:

local k = next(t, nil)
while k ~= nil do
    if k ~= "skip_me" then
        print(k, t[k])
    end
    k = next(t, k)
end

Summary

AspectDetail
Starting callnext(t, nil) to get the first entry
Advancingnext(t, previous_key)
End of tableReturns nil
Empty tablenext(t) returns nil
OrderNot guaranteed — not insertion order, not sorted
Safe to modifyExisting keys only; never add new keys during iteration
Internal usepairs() calls next internally

next is rarely called directly in everyday code — pairs() handles most use cases. But when you need manual iteration control, need to detect empty tables efficiently, or want to understand how Lua’s iteration machinery works, next is the function to reach for.

See Also