0.9 - 2024-06-26


  • filesystem.clock.time_point.seconds_since_unix_epoch.

  • New bindings in init.script related to mount_setattr() (Linux).


  • is_block_file() renamed to is_block_device().

  • is_character_file() renamed to is_character_device().

0.8 - 2024-05-19


  • Add functions dial() and listen() from the likes of Golang.

  • New way of embedding builtin modules to a custom binary/launcher.


  • The code is now dual-licensed MIT and BSL-1.0. User picks either of these options. The motivation is to make it easier to contribute code back to LuaJIT’s community. Previously it was only easy to contribute code back to the Boost’s community.

  • Split module unix into submodules.

    • unix.datagram_socketunix.datagram.socket.



    • unix.seqpacket_socketunix.seqpacket.socket.

    • unix.seqpacket_acceptorunix.seqpacket.acceptor.

  • Removed tables for bit.bor() operations. Flags are now passed as lists of strings.

    • file.open_flag.

    • ip.address_info_flag.

    • ip.message_flag.

    • tls.context_flag.

    • unix.message_flag.

  • Actor messaging is now more asynchronous than before. Emilua intentionally used lots of synchronization points internally for actor messaging as it’d be easier to remove synchronization than to add (if the chosen semantics proved to be wrong later). Fast-forward to the present and it’s clear now that the excessive synchronization is not really useful. The excessive synchronization was not getting in the way for anything, but it wasn’t needed either. The new semantics (channel.send is fully asynchronous to the target actor) are lighter to implement as well so it might benefit some workloads. channel.send still retains some of the previous properties such as most of the error-checking (e.g. detecting channel-closed for many scenarios), post semantics in ASIO-lingo (fiber goes to the end of the execution queue so other fibers have a chance to run), and interruptibility. We could go further and just don’t reschedule the fiber nor check for interruptions at all, but I feel more comfortable doing small gradual changes to see how the changes play out.

0.7 - 2024-04-17


  • Add seccomp support.

  • Add filesystem.mkdir() to complement filesystem.create_directory().

  • filesystem.mode() accepts new arguments now.

  • Add filesystem.chroot().

  • filesystem.current_working_directory() accepts file_descriptor objects on UNIX now.

  • Add extra optional parameter to filesystem.mknod().

  • Add filesystem.clock.epoch(). It’s useful to set the last modification date of every file in some directory for the purposes of a reproducible build or something. However there are more attributes besides last-write-time you need to care about if you’re planning to play with reproducible builds (be warned!).

  • Add filesystem.clock.unix_epoch() and

  • Add more POSIX bindings to init.script API.

  • Add the flock() family to and file.random_access.

  • Now it’s possible to configure Landlock mode for the calling process or system.spawn() subprocesses.

  • Add byte_span methods for primitive types serialization (e.g. reading i32le from a 4-sized buffer). It also works as an endianness handling interface. 64-bit integers are omitted from the interface because LuaJIT only offers a hacky way to handle them.


  • Make nullable. That’s useful for synchronization when multiple fibers are observing parts of subprocess state.

  • Allow file_descriptor.close() to be called multiple times in a row.

  • Change filesystem.copy_file() parameters.

  • Change every name in the module filesystem from hard_* to hard* (e.g. create_hard_link() to create_hardlink()). This C++17 convention is dumb and Python’s pathlib is the one who got it right.

  • Change default record_separator in stream.scanner to "\n".

  • Always start subprocess-based actors with umask 022.

  • Change system.spawn() parameters from nsenter_* to setns_*.


  • Close file descriptors from builtin PID1 so EPIPE propagates sooner.

  • Fix races in filesystem.current_working_directory(). Now fchdir() is used.

  • Small documentation issues.

  • Avoid potential IO double-flush on FreeBSD after fork().

0.6 - 2024-01-06


  • Add FreeBSD’s jails support.

  • Add function format() to format strings. The implementation uses C++'s libfmt.

  • Add more functions to the module filesystem: exists(), is_block_file(), is_character_file(), is_directory(), is_fifo(), is_other(), is_regular_file(), is_socket(), is_symlink(), mode(). It was already possible to query for these attributes. These functions were added as an extra convenience.

  • Add yet more functions to the module filesystem: mkfifo(), mknod(), makedev().

  • New UNIX socket options to retrieve security labels and credentials from the remote process.

  • file_descriptor implemented for Windows pipes and

  • Many improvements to Windows version of system.spawn().


  • Convert decomposition functions from filesystem.path to properties: root_name, root_directory, root_path, relative_path, parent_path, filename, stem, extension.

  • Convert some filesystem.path properties to string: root_name, root_directory, filename, stem, extension.

  • filesystem.path.iterator() will return strings at each iteration now.


  • Remove HTTP & WebSocket classes. They should be offered as separate plugins.

0.5 - 2023-12-03


  • Add mutex.try_lock().

  • Add module recursive_mutex.

  • Add module future.

  • Add filesystem.chown().

  • Enable IPC-based actors on all UNIX systems.

  • Add Linux Landlock support.

  • Add FreeBSD Capsicum support.


  • spawn_vm() performs the same module path resolution from require() now. That means it’s possible to use root-imports from spawn_vm().

  • spawn_vm() parameters refactored (API break).

0.4 - 2023-04-03


  • A new byte_span type akin to Go slices is used for IO ops.

  • Actor channels now can transceive file descriptors.

  • Support for Linux namespaces. Now you can set up sandboxes and run isolated actors (or just the well-known containers).

  • Modules ip and tls grew a lot. The API for sockets now supports IO ops on byte_span instances, and plenty of new functions and classes (including UDP) were added.

  • New modules.

    • time: clocks and timers.

    • pipe.

    • unix: UNIX domain sockets.

    • serial_port: serial ports.

    • system: UNIX signals, CLI args, env vars, process credentials, and much more.

    • file: file IO. Only available on systems with proactors (e.g. Windows with IOCP, and Linux with io_uring). BSD can still be supported later (with kqueue + POSIX AIO).

    • filesystem: portable path-manipulation, and plenty of filesystem operations & algorithms.

    • stream: AWK-inspired scanner and common stream algorithms.

    • regex: Basic regex functions. The interface has been inspired by C++, Python and AWK.

    • generic_error: portable error comparison for filesystem, sockets, and much more.

    • asio_error: errors thrown by the asio layer.

    • websocket.

  • Lua programs can define their own error categories now.

  • Several new OS-specific APIs (e.g. Linux capabilities, and Windows' TransmitFile()).

  • Add http.request.upgrade_desired().

  • http.socket can work on top of UNIX domain stream sockets now.

  • Documentation can now be installed as manpages.

  • Support for io_uring.


  • Upgrade to C++20. The motivating feature for the upgrade was std::atomic<std::weak_ptr<T>>. However, other C++20 features are being used as well.

  • Moved steady_timer to the new module time.

  • tls.ctx renamed to tls.context.

  • inbox.recv() renamed to inbox.receive()

  • Module cond renamed to condition_variable.

  • renamed to error_code.category.

  • spawn_ctx_threads() renamed to spawn_context_threads().

  • inherit_ctx renamed to inherit_context in spawn_vm().

  • Now Emilua is less liberal on accepted values for env var EMILUA_COLORS.

  • Finer-grained cancellation of IO ops.

  • Locales are set at application startup.

  • The build system now makes use of Meson’s wrap system.


  • Removed println().

  • Removed sleep_for. Its functionality has been replaced by the module time.

  • Removed ip.tcp.resolver. Its functionality has been replaced by ip.get_address_info().


  • Bug fixes.

0.3 - 2021-03-04


  • HTTP request and response objects now use read-write locks and there is some limited sharing that you can do with them without stumbling upon EBUSY errors.

  • Improvements to the module system (that’s the main feature for this release). You should be able to use guix as the package manager for your emilua projects.

  • EMILUA_PATH environment variable.

  • Native plugins API (it can be disabled at build configure time).

  • Add logging module.

  • Add manpage.

  • --version CLI arg.

  • Build configure options to disable threading.


  • Use fmtlib from host system.

0.2 - 2021-01-31


  • Add HTTP query function: http.request.continue_required().


  • Refactor module system. The new module system is incompatible with the previous one. Please refer to the documentation.

  • Numeric values for error codes changed.


  • Remove failed_to_load_module error code. Now you should see "iostream error" or other more informative error reasons upon a failed module load.


  • Fix build when compiler is GCC.