Skip to content

Latest commit



3956 lines (2660 loc) · 110 KB

File metadata and controls

3956 lines (2660 loc) · 110 KB

LibUV in Lua

The luv project provides access to the multi-platform support library libuv in Lua code. It was primarily developed for the luvit project as the built-in uv module, but can be used in other Lua environments.

More information about the core libuv library can be found at the original libuv documentation page.

TCP Echo Server Example

Here is a small example showing a TCP echo server:

local uv = require("luv") -- "luv" when stand-alone, "uv" in luvi apps

local server = uv.new_tcp()
server:bind("", 1337)
server:listen(128, function (err)
  assert(not err, err)
  local client = uv.new_tcp()
  client:read_start(function (err, chunk)
    assert(not err, err)
    if chunk then
print("TCP server listening at port 1337") -- an explicit run call is necessary outside of luvit

Module Layout

The luv library contains a single Lua module referred to hereafter as uv for simplicity. This module consists mostly of functions with names corresponding to their original libuv versions. For example, the libuv function uv_tcp_bind has a luv version at uv.tcp_bind. Currently, only two non-function fields exists: uv.constants and uv.errno, which are tables.

Functions vs Methods

In addition to having simple functions, luv provides an optional method-style API. For example, uv.tcp_bind(server, host, port) can alternatively be called as server:bind(host, port). Note that the first argument server becomes the object and tcp_ is removed from the function name. Method forms are documented below where they exist.

Synchronous vs Asynchronous Functions

Functions that accept a callback are asynchronous. These functions may immediately return results to the caller to indicate their initial status, but their final execution is deferred until at least the next libuv loop iteration. After completion, their callbacks are executed with any results passed to it.

Functions that do not accept a callback are synchronous. These functions immediately return their results to the caller.

Some (generally FS and DNS) functions can behave either synchronously or asynchronously. If a callback is provided to these functions, they behave asynchronously; if no callback is provided, they behave synchronously.


Some unique types are defined. These are not actual types in Lua, but they are used here to facilitate documenting consistent behavior:

  • fail: an assertable nil, string, string tuple (see Error handling)
  • callable: a function; or a table or userdata with a __call metamethod
  • buffer: a string or a sequential table of strings
  • threadargs: variable arguments (...) of type nil, boolean, number, string, or userdata, numbers of argument limited to 9.


This documentation is mostly a retelling of the libuv API documentation within the context of luv's Lua API. Low-level implementation details and unexposed C functions and types are not documented here except for when they are relevant to behavior seen in the Lua module.

Error Handling

In libuv, errors are negative numbered constants; however, while those errors are exposed through uv.errno, the functions used to handle them are not exposed to luv users. Instead, if an internal error is encountered, the luv function will return to the caller an assertable nil, err, name tuple.

  • nil idiomatically indicates failure
  • err is a string with the format {name}: {message}
    • {name} is the error name provided internally by uv_err_name
    • {message} is a human-readable message provided internally by uv_strerror
  • name is the same string used to construct err

This tuple is referred to below as the fail pseudo-type.

When a function is called successfully, it will return either a value that is relevant to the operation of the function, or the integer 0 to indicate success, or sometimes nothing at all. These cases are documented below.


A table value which exposes error constants as a map, where the key is the error name (without the UV_ prefix) and its value is a negative number. See Libuv's Error constants page for further details.

  • E2BIG: argument list too long.
  • EACCES: permission denied.
  • EADDRINUSE: address already in use.
  • EADDRNOTAVAIL: address not available.
  • EAFNOSUPPORT: address family not supported.
  • EAGAIN: resource temporarily unavailable.
  • EAI_ADDRFAMILY: address family not supported.
  • EAI_AGAIN: temporary failure.
  • EAI_BADFLAGS: bad ai_flags value.
  • EAI_BADHINTS: invalid value for hints.
  • EAI_CANCELED: request canceled.
  • EAI_FAIL: permanent failure.
  • EAI_FAMILY: ai_family not supported.
  • EAI_MEMORY: out of memory.
  • EAI_NODATA: no address.
  • EAI_NONAME: unknown node or service.
  • EAI_OVERFLOW: argument buffer overflow.
  • EAI_PROTOCOL: resolved protocol is unknown.
  • EAI_SERVICE: service not available for socket type.
  • EAI_SOCKTYPE: socket type not supported.
  • EALREADY: connection already in progress.
  • EBADF: bad file descriptor.
  • EBUSY: resource busy or locked.
  • ECANCELED: operation canceled.
  • ECHARSET: invalid Unicode character.
  • ECONNABORTED: software caused connection abort.
  • ECONNREFUSED: connection refused.
  • ECONNRESET: connection reset by peer.
  • EDESTADDRREQ: destination address required.
  • EEXIST: file already exists.
  • EFAULT: bad address in system call argument.
  • EFBIG: file too large.
  • EHOSTUNREACH: host is unreachable.
  • EINTR: interrupted system call.
  • EINVAL: invalid argument.
  • EIO: i/o error.
  • EISCONN: socket is already connected.
  • EISDIR: illegal operation on a directory.
  • ELOOP: too many symbolic links encountered.
  • EMFILE: too many open files