# 3.7.0

Date: 2026-04-22
Tag: 3.7.0

## Overview

Tarantool 3.x is the recommended release series. Users of Tarantool 2.11 are
encouraged to update to the latest 3.x release.

This release introduces 11 improvements and resolves 29 bugs since 3.6.2.

Please consider the full list of user-visible changes below.

## Compatibility

Tarantool 2.x and 3.x are compatible in the binary data layout, client-server
protocol, and replication protocol. It means upgrade may be performed with zero
downtime for read requests and the order-of-network-lag downtime for write
requests.

Please follow the [upgrade procedure][upgrade] to plan your update actions.

Users of Tarantool 2.x may be interested in the [compat][compat] options that
allow to imitate some 2.x behavior. This allows to perform application code
update step-by-step, not all-at-once.

[compat]: https://www.tarantool.io/en/doc/latest/reference/configuration/configuration_reference/#compat

[upgrade]: https://www.tarantool.io/en/doc/latest/book/admin/upgrades/

## Functionality added or changed

### App

* Exposed new `tcp_server_create` and `tcp_server_loop` handles to the `socket`
  module so a listening socket and accept loop can be driven from different
  threads. The existing `socket.tcp_server` behavior remains unchanged and
  is equivalent to a pair of `tcp_server_create()`, `tcp_server_loop()` calls.

### Core

* Introduced experimental support for application threads. Like the main thread
  an application thread runs an event loop and has a Lua state with most
  built-in modules available, but it cannot access the database directly.
  Application threads are configured with the new `threads` configuration
  option. For calling other threads, including the main thread, the new Lua
  module `experimental.threads` has been added (gh-12206).
* Usage of custom collations is now deprecated. Support for custom collations
  is scheduled to be dropped in Tarantool 4.0. Newer Tarantool versions will
  not recover if there are custom collations in the database (gh-12209).
* Introduced `box.iproto.export()` for exposing a Lua function to `IPROTO_CALL`
  requests without polluting the global Lua namespace (gh-10036).

### Replication

* Added the `replication.linearizable_quorum` option controlling the number of
  replicas a node must synchronize with before performing a linearizable
  transaction. The default value is `N - Q + 1`, where `N` stands for the count
  of replicas in the replica set and `Q` is the evaluated
  `replication_synchro_quorum` value. The same formula was used internally prior
  to this change (gh-11876).

### Config

* Now it is allowed to assign and delete nested fields inside schema nodes
  of the `any` type using deep paths (gh-10204).
* Added `config:wait_status(statuses, [timeout])` to wait until the instance
  reaches one of the specified configuration statuses and returns the actual
  status observed when the wait finishes (gh-12389).
* Added the `env` option to `config:get()` to explicitly control whether
  `TT_*` environment variables are taken into account (gh-9824).

### Log

* With the `verbose` option enabled in `http.client`, libcurl debug logs
  are now routed to the Tarantool log instead of stderr (gh-12392).

### Metrics

* Updated the `metrics` submodule to 1.7.0.

  Changes in 1.7.0:

  - graphite: Added an ability to send metrics to multiple servers.
  Backward compatibility with previous plugin versions is preserved.
  From now on, the `init` method assigns a unique name to the created fiber
  using the incoming graphite server `opts` (if provided). Added a new `stop()`
  method to stop all fibers started by the plugin ([gh-540][mgh-540]).

  - Deleting a replica via `box.space._cluster:delete()` no longer leaves
  information about that replica in the metrics (it was only removed after
  a cluster restart) ([gh-538][mgh-538]).

[mgh-540]: https://github.com/tarantool/metrics/pull/540
[mgh-538]: https://github.com/tarantool/metrics/pull/538

### Tools

* Introduced the `misc.memprof.available` and `misc.sysprof.available` flags to
  determine whether the corresponding profiler is available for the current
  Tarantool build (gh-12215).

## Bugs fixed

### Core

* Fixed a bug where `.xlog.inprogress` files were not automatically deleted
  during server startup if the `wal_dir` value was not the default (gh-12081).

### Vinyl

* Fixed `vinyl_memory` overrun during recovery when the memory limit is lower
  than at the previous start (gh-12390).

### Replication

* Fixed a bug where replication could get stuck upon receipt of a 'promote'
  entry from a newly elected leader. This was likely to happen when the receiver
  itself had been a leader not long ago and still had some transactions in the
  synchro queue not yet written to the journal (gh-12205).
* Fixed a bug where a replica on subscribe could get stuck in the `sync` state
  for the duration of `replication.timeout`. This issue was observable in
  `box.info.replication[...].upstream` and could lead to temporary
  inconveniences, such as the inability to run `box.ctl.promote()` (when
  `election_mode` was not `off`) (gh-12025).

### LuaJIT

Backported patches from the vanilla LuaJIT trunk (gh-12134). The following
issues were fixed as part of this activity:

* Added `ffi.abi("dualnum")`.
* Fixed stack checks in varargs calls in the GC64 build.
* Fixed stack checks in `pcall()`/`xpcall()` in the GC64 build.
* Fixed the allocation limit for the no-JIT build.
* Fixed handling of OOM errors on stack resizing in `coroutine.resume()` and
  `lua_checkstack()`.
* Fixed recording of loops with a `-0` `step` value or `NaN` control values.
* Fixed error reporting when an error occurs during error handling.
* Fixed a dangling reference for FFI callbacks.
* Fixed `BC_UNM` for a `-0` argument in the dual-number mode.
* Fixed narrowing of unary minus in the dual-number mode.
* Fixed recording of `string.byte()`, `string.sub()`, and `string.find()`.
* Fixed missing type conversion for `BC_FORI` slots in the dual-number mode.
* Fixed various corner cases in VM events.
* Fixed constructor index resolution recording in the JIT compiler.
* Fixed a UBSan warning in `unpack()`.
* Fixed snapshot purge while recording a function header.

### Config

* Fixed a startup failure when a Tarantool 3.x instance configured via
  the declarative config joined a 2.x replica set, where the master had
  no instance or replica set names stored in its snapshot (gh-10426).
* Fixed a bug in the supervised bootstrap strategy when a replica could hang on
  startup while joining an already bootstrapped replica set (gh-11318).

### Datetime

* Fixed an assertion failure on an ambiguous case where day of year (`yday`,
  which defines calendar month and month day implicitly) and calendar month
  (without a month day) were both defined in the date text. Now such case is
  detected and an error is thrown (gh-11347).
* Fixed `tzoffset` calculations for cases like `new({timestamp=x, tz='Zone'})`
  (gh-12412).
* Fixed inconsistency between dates produced by `new({tzoffset=x})`
  and `d:set({tzoffset=x})` where `d.tz ~= ''` comes before `set()`
  (gh-7680, gh-12416).
* Now `datetime.new()` and `datetime_object:set()`
  check the timestamp value to be in the valid range (gh-12147).

### Election

* Fixed a bug where a newly elected leader could become writable (`box.info.ro`
  is `false`) immediately after `box.info.election.state == 'leader'` but before
  it claimed the synchronous transactions queue (`box.info.synchro.queue.owner`
  is not this node). This could occur only when the synchronous queue was
  previously unclaimed, which typically happens on cluster startup (gh-12333).
* Fixed a bug where `box.ctl.promote()` returned before the instance became
  writable (gh-10040).
* Fixed a bug where a replica could crash or exhibit undefined behavior when
  the election leader sent this replica a synchronous replication control
  command (promotion or demotion), but the replica received it just before
  performing a cascading journal rollback. This could happen if the
  `wal.queue_max_size` setting was reached (gh-12557).
