tostring
tostring(v) tostring converts any Lua value into a human-readable string. Numbers, booleans, and nil all convert predictably. Tables, functions, threads, and userdata get a pointer address like table: 0x7f8a3c102030 — the object’s memory location in the C implementation. The original value is never modified.
Signature
tostring(v)
Parameters:
v— any Lua value
Returns: string
Basic Types
tostring(42) --> "42"
tostring(3.14) --> "3.14"
tostring(-100) --> "-100"
tostring(true) --> "true"
tostring(false) --> "false"
tostring(nil) --> "nil"
Numbers are formatted as you’d write them in source. No rounding, no trailing zeros for integers.
Complex Types
tostring({}) --> "table: 0x7f8a3c102030"
tostring(print) --> "function: 0x7f8a3c102100"
tostring(coroutine.create(function() end))
--> "thread: 0x7f8a3c102200"
The hex address is the object’s memory location. Two identical-looking tables always produce different addresses — they are different objects.
Why You Need It
Lua’s .. concatenation operator requires strings on both sides. Without tostring, converting a number or boolean for concatenation raises an error:
"score: " .. 42 --> error: attempt to concatenate string with number
"score: " .. tostring(42) --> "score: 42"
This is the main reason tostring exists — enabling string building with non-string values.
Practical Patterns
Debug Logging
function dump(value)
print(tostring(value))
end
dump(42) --> 42
dump({a = 1}) --> table: 0x...
dump(nil) --> nil
tostring on a table only shows its address, not contents. For table contents, you need a custom pretty-printer.
Safe Concatenation
function label(key, value)
return key .. ":" .. tostring(value)
end
label("count", 5) --> "count:5"
label("name", nil) --> "name:nil"
label("active", true) --> "active:true"
Wrapping values in tostring lets you build strings without type-checking every argument.
Default Values
function greet(name)
name = tostring(name)
if name == "" or name == "nil" then
return "Hello, World"
end
return "Hello, " .. name
end
greet("Alice") --> "Hello, Alice"
greet(nil) --> "Hello, nil"
greet("") --> "Hello, World"
tostring vs String Concatenation
Lua 5.3+ handles "" .. 42 implicitly — the left string operand triggers conversion. But if you try 42 .. "", Lua evaluates the left side first as a number and the .. operator can’t start with a number, so use tostring(42) to be explicit:
"" .. 42 --> "42" (works)
tostring(42) .. "" --> "42" (explicit and clear)
__tostring Metamethod
Tables can define a custom string representation via the __tostring metamethod:
local point = setmetatable({x = 1, y = 2}, {
__tostring = function(self)
return string.format("(%d, %d)", self.x, self.y)
end
})
print(tostring(point)) --> "(1, 2)"
Note: tostring in standard Lua does not call __tostring. This works because print calls tostring internally which can use __name in some contexts. For cross-version reliability, use a dedicated __tostring method and call it explicitly rather than relying on print/tostring to pick it up.
See Also
- /reference/core-functions/ref-print/ — output values to stdout
- /reference/core-functions/ref-type/ — get the type name of a value
- /guides/lua-serialization/ — turning tables into storable strings