Tarantool CE/EE Documentation portal logo
Support
Updated at November 2, 2026   03:35 PM

Application threads

Application threads allow application code to use additional threads for offloading work from the main thread.

Like the main thread, each application thread runs an independent event loop and a Lua interpreter and has most Tarantool built-in modules available.

Enabling application threads

To enable application threads, add the top-level section threads with the sub-section groups to the configuration file. For example, to create two application thread groups, http with one thread and app with four threads, use the following configuration:

threads:  groups:    - name: http      size: 1    - name: app      size: 4

The thread group tx with one thread is always created implicitly. It can be used for calling the main thread from other threads, as described below.

Using application threads

For interacting with application threads, the built-in threads Lua module was introduced. It offers the following functions:

  • threads.call() calls a function on a thread group.
  • threads.export() exports a local Lua function so that it can be called with threads.call() from other threads.
  • threads.eval() executes a Lua expression on a thread group.
  • threads.info() returns information about configured thread groups and the current thread.

The threads module is available in all threads. It can be used in the main thread even before Tarantool is configured, but only with the tx thread group as a target apparently, because application thread groups are created during configuration.

Like the main thread, application threads can expose functions through IPROTO, by calling box.iproto.export. If a function is exposed in one or more threads, IPROTO will forward CALL requests for this function to one of the threads where the function is exposed. To call a function in an application thread, the user must have the lua_call privilege for this function or be the admin.

Example

Below is an example of exposing a function through IPROTO in application threads.

iproto:  listen:    - uri: localhost:3301credentials:  users:    client:      password: secret      privileges:        - permissions: [execute]          lua_call: [test_func]threads:  groups:    - name: app      size: 4app:  module: test_maingroups:  group-001:    replicasets:      replicaset-001:        instances:          instance-001: {}
-- test_main.lualocal threads = require('threads')threads.eval('app', [[require('test_thread')]])
-- test_thread.lualocal threads = require('threads')box.iproto.export('test_func', function()    local info = threads.info()    return string.format('Hello from thread %s/%d',                         info.group_name, info.thread_id)end)
-- test_client.lualocal net = require('net.box')local conn = net.connect(3301, {user = 'client', password = 'secret'})for i = 1, 10 do    print(conn:call('test_func'))endos.exit()

To run the example, execute the following command:

tarantool -c config.yaml -n instance-001

And run the client in another terminal:

tarantool test_client.lua

It will print something like this:

Hello from thread app/4Hello from thread app/2Hello from thread app/1Hello from thread app/2Hello from thread app/4Hello from thread app/4Hello from thread app/4Hello from thread app/3Hello from thread app/2Hello from thread app/2

Read views in application threads

A read view opened in the main thread can be shared with an application thread started via box.cfg{app_threads = ...}. To do this, pass the read view's id to the application thread and open it there by id:

box.cfg{app_threads = 1}box.schema.space.create('test')box.space.test:create_index('primary')box.space.test:replace({1, 'x'})local rv = box.read_view.open({name = 'shared_read_view'})local threads = require('threads')threads.eval('app', [[  local rv = box.read_view.open({id = ...})  return rv.space.test:select()]], {rv.id})

A new read view can still be created only in the main thread: calling box.read_view.open() without id in an application thread raises an error. Similarly, box.read_view.list() can be called only in the main thread.

If a read view in use by an application thread is closed in the main thread, it isn't deleted immediately — it switches to the close_pending status. A read view in this status can't be used in the main thread or reopened in another thread, but threads that already opened it can keep using it until they stop. Once the last user stops using it, the read view is deleted globally — either explicitly or via Lua garbage collection.