High-performance Node.js driver for Tarantool 1.7+ with support for Node.js v20+.
Based on go-tarantool and implements Tarantool's binary protocol. Code architecture and performance features in version 4 borrowed from ioredis.
Uses msgpackr as the high-performance MsgPack encoder/decoder by default.
TarantoolConnection.socket.on('close') for closure notifications or handle rejected promise errors.
- 📦 Installation
- ⚙️ Configuration
- 📝 Usage Example
- 📚 API Reference
- 🔍 Debugging
- 📖 Related Documentation
- Performance Guide - Optimization tips for maximum throughput 🚀
- Benchmarks - Performance comparisons and results 📊
- Changelog - Release notes and version history 📋
- 🤝 Contributions
npm install --save tarantool-drivernew Tarantool([port], [host], [options])Creates a Tarantool instance, extends EventEmitter.
Connection Events:
reconnecting- Emitted when the client attempts to reconnect; first argument is retry delay in millisecondsconnect- Emitted when successfully connected and authenticated (if credentials provided); first argument is an object withhostandportof the Tarantool server
| Option | Type | Default | Description |
|---|---|---|---|
port |
number | string | Object |
3301 |
Port of the Tarantool server, or a URI string (see Tarantool configuration docs), or options object |
host |
string | Object |
"localhost" |
Host of the Tarantool server; when first argument is a URL string, this argument becomes the options object |
path |
string |
null |
Unix socket path of the Tarantool server (overrides host/port) |
username |
string |
null |
Username for authentication when connected |
password |
string |
null |
Password for authentication when connected |
timeout |
number |
10000 |
Milliseconds before timeout during initial connection or .disconnect() call |
tls |
Object |
null |
If specified, uses TLS instead of plain TCP. Accepts any options from tls.createSecureContext() |
keepAlive |
boolean |
true |
Enables TCP keep-alive functionality (recommended) |
noDelay |
boolean |
true |
Disables Nagle's algorithm (recommended for lower latency) |
lazyConnect |
boolean |
false |
If true, delays automatic connection until first command is called |
tupleToObject |
boolean |
false |
Converts response tuples from arrays to objects with field names as keys |
enableAutoPipelining |
boolean |
false |
🚀 Auto-pipelines all commands during event loop iteration (improves throughput 2-4x with slight latency trade-off) |
enableOfflineQueue |
boolean |
true |
If false, rejects commands when not connected instead of queuing them |
commandTimeout |
number |
null |
Maximum execution time in milliseconds before rejecting the command (recommended: 500+) |
sliderBufferInitialSize |
number |
Buffer.poolSize * 10 |
Initial size of buffer pool; increase for high-load scenarios, decrease for resource-constrained systems |
prefetchSchema |
boolean |
true |
Automatically loads space schema on connection |
reserveHosts |
array |
[] |
Array of fallback hosts for failover (as connection strings, objects, or port numbers) |
beforeReserve |
number |
2 |
Number of reconnection attempts before trying next reserve host |
connectRetryAttempts |
number |
10 |
Maximum connection attempts (including reserve hosts) before rejecting .connect() promise |
retryStrategy |
function |
See below | Custom retry delay calculation function |
MsgPack |
Class |
MsgPack |
Custom MsgPack encoder/decoder implementation |
Connector |
Class |
StandaloneConnector |
Custom connection implementation |
By default, the driver automatically reconnects when the connection is lost (except after manual .disconnect() or .quit()).
Control reconnection timing with the retryStrategy option:
const tarantool = new Tarantool({
// Default implementation
retryStrategy: function (times) {
return Math.min(times * 50, 2000);
}
});The function receives times (nth reconnection attempt) and returns milliseconds to wait before next attempt. Return a non-numeric value to stop retrying; manually call .connect() to resume.
This feature is inspired by ioredis
const connection = new Tarantool({
host: 'primary.example.com',
port: 3301,
username: 'user',
password: 'secret',
reserveHosts: [
'user:pass@secondary.example.com:3301',
'/var/run/tarantool.sock',
'127.0.0.1:3301'
],
beforeReserve: 1
});
// Attempts: primary → secondary → localhost → primary (cycle repeats)const Tarantool = require('tarantool-driver');
const conn = new Tarantool('user:password@localhost:3301');
// Select data
conn.select(512, 0, 10, 0, 'eq', [50])
.then(results => {
console.log('Results:', results);
})
.catch(err => {
console.error('Error:', err);
});
// Simple callback style
conn.select(512, 0, 10, 0, 'eq', [50], {}, (err, results) => {
if (err) {
console.error('Error:', err);
} else {
console.log('Results:', results);
}
});Establishes connection to the Tarantool server.
Returns: Promise that resolves when connected and authenticated, rejects on error.
await conn.connect();Closes the connection immediately. Pending commands may be lost.
Returns: undefined
conn.disconnect();Gracefully closes the connection after all sent commands complete.
Returns: Promise that resolves after all pending commands finish and connection closes.
await conn.quit();Internal method. Authenticates with Tarantool using CHAP-SHA1 mechanism.
Note: Called automatically during connection if credentials are provided.
See Tarantool authentication docs for details.
Performs a SELECT query on the database.
Parameters:
spaceId(number|string) - Space ID or nameindexId(number|string) - Index ID or namelimit(number) - Maximum records to returnoffset(number, default:0) - Number of records to skipiterator(string, default:'eq') - Iterator type:'eq','req','all','lt','le','ge','gt','bitsAllSet','bitsAnySet','bitsAllNotSet','overlaps','neighbor'key(Array) - Search key tupleopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, results)
Returns: Promise resolving to array of tuples. If callback provided, returns undefined.
Examples:
// By space/index ID
const results = await conn.select(512, 0, 10, 0, 'eq', [50]);
// By space/index name
const results = await conn.select('users', 'primary', 10, 0, 'eq', [50]);
// With callback
conn.select(512, 0, 10, 0, 'eq', [50], {}, (err, results) => {
if (err) console.error(err);
else console.log(results);
});
// With UUID
const results = await conn.select(
'users', 'id', 1, 0, 'eq',
[conn.packUuid('550e8400-e29b-41d4-a716-446655440000')]
);tarantool.selectCb(spaceId, indexId, limit, offset, iterator, key, successCb, errorCb, [opts]) ⇒ undefined
Deprecated. Use .select() with callback parameter instead.
Legacy callback-style select. Parameters order differs from .select().
conn.selectCb(512, 0, 10, 0, 'eq', [50],
(results) => console.log(results),
(error) => console.error(error)
);Inserts a tuple into the database.
Parameters:
spaceId(number|string) - Space ID or nametuple(Array) - Data tuple to insertopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to the inserted tuple.
const result = await conn.insert('users', [1, 'Alice', 'alice@example.com']);Replaces a tuple in the database (inserts if not exists).
Parameters:
spaceId(number|string) - Space ID or nametuple(Array) - Data tuple to replaceopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to the replaced or inserted tuple.
const result = await conn.replace('users', [1, 'Alice Updated', 'alice.new@example.com']);Updates a tuple in the database.
Parameters:
spaceId(number|string) - Space ID or nameindexId(number|string) - Index ID or namekey(Array) - Key tuple to identify recordops(Array<Array>) - Update operations:[operator, fieldId/fieldName, value]opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to the updated tuple.
Operators: '=', '+', '-', '&', '|', '^', ':', '!', '#', '%' - see Tarantool update docs.
// Update field 2 to new value
const result = await conn.update('users', 'primary', [1], [['=', 2, 'New Name']]);
// Increment field by 1
const result = await conn.update('users', 'primary', [1], [['+', 'counter', 1]]);Deletes a tuple from the database.
Parameters:
spaceId(number|string) - Space ID or nameindexId(number|string) - Index ID or namekey(Array) - Key tuple to identify recordopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to the deleted tuple.
const deleted = await conn.delete('users', 'primary', [1]);Updates or inserts a tuple (insert if not exists, update if exists).
Parameters:
spaceId(number|string) - Space ID or nametuple(Array) - Tuple to insert if key not foundops(Array<Array>) - Update operations if key existsopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise that resolves (typically with no value).
await conn.upsert('users', [1, 'Alice', 'alice@example.com'], [['+', 'counter', 1]]);Transactions use streams to maintain isolation. Use within connection.transaction() context.
Creates a new transaction context for executing commands.
Returns: Transaction object that routes commands to same stream.
const txn = conn.transaction();
await txn.insert('users', [1, 'Alice']);
await txn.begin();
await txn.update('users', 'primary', [1], [['=', 2, 'Alice Updated']]);
await txn.commit();Starts a transaction.
Parameters:
transTimeoutSec(number, default:60) - Transaction timeout in secondsisolationLevel(number, default:0) - Isolation level (0 = default)opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise that resolves when transaction begins.
const txn = conn.transaction();
await txn.begin(120, 0);
try {
await txn.insert('users', [1, 'Alice']);
await txn.insert('logs', ['INSERT user 1']);
await txn.commit();
} catch (err) {
await txn.rollback();
throw err;
}Commits the transaction.
Parameters:
opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise that resolves when transaction commits.
Rolls back the transaction.
Parameters:
opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise that resolves when transaction rolls back.
Calls a Lua function on the server.
Parameters:
functionName(string) - Name of the function to callargs(Array, optional) - Function arguments passed as arrayopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to function result (typically array for multiple returns).
Note: Arguments must be passed as array since v4.0.0.
// Server-side function
// box.schema.func.create('get_user', {if_not_exists = true})
// function get_user(id) return box.space.users:select{id} end
const results = await conn.call('get_user', [42]);Evaluates Lua code on the server.
Parameters:
expression(string) - Lua code to evaluateargs(Array, optional) - Variables passed to Lua codeopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to evaluation result.
const userId = await conn.eval('return box.session.user()', []);
const customResult = await conn.eval(
'return select(1, ...)',
[1, 2, 3, 4, 5]
);Executes SQL query on the server (Tarantool 2.1+).
Parameters:
sqlQuery(string|PreparedStatement) - SQL query string or prepared statement instancebindParams(Array, optional) - Bind parametersopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to query results.
"space_name"
await conn.sql('INSERT INTO tags VALUES (?, ?)', ['tag_1', 1]);
const prepStmt = await conn.prepare('INSERT INTO tags VALUES (?, ?)');
await conn.sql(prepStmt, ['tag_2', 50]);
const results = await conn.sql('SELECT * FROM "tags"');Prepares an SQL statement for repeated execution.
Parameters:
sqlQuery(string) - SQL query stringopts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to PreparedStatement object which can be passed later as .sql(prepStmtObj, ...) parameter.
const stmt = await conn.prepare('SELECT * FROM users WHERE id = ?');
const results = await conn.sql(stmt, [1]);Sends a PING command to the server.
Parameters:
opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to true if server responds.
const isAlive = await conn.ping();Sends an ID (handshake) command to negotiate protocol version, features, and authentication type with the server.
Parameters:
version(number, default:3) - Protocol version to usefeatures(Array, default:[1]) - List of supported featuresauth_type(string, default:'chap-sha1') - Authentication type (e.g.,'chap-sha1')opts(Object, optional) - Options objectcb(Function, optional) - Callback function(error, result)
Returns: Promise resolving to server identity and capabilities information.
// Basic handshake with defaults
const serverInfo = await conn.id();
// Custom protocol negotiation
const serverInfo = await conn.id(3, [1, 2], 'chap-sha1');Starts a pipeline for batching commands. Commands are queued in memory without sending to server immediately.
Returns: Pipeline object for method chaining.
Performance: 🚀 Improves throughput by 300%+ compared to individual requests.
const results = await conn.pipeline()
.insert('users', [1, 'Alice'])
.insert('users', [2, 'Bob'], null /* opts */, (error, result) => {
// some processing logic
// "error" and "result" arguments are corresponding exactly to this request
})
.select('users', 'primary', 10, 0, 'eq', [1])
.exec();
// Results format: [[err1, res1], [err2, res2], [err3, res3]]Executes all queued commands in a single network call.
Returns: Promise resolving to PipelineResponse instance (extends Array) containing [error, result] pairs for each command.
Clears the pipelined commands queue.
Returns: undefined
PipelineResponse Methods:
findPipelineError()- Returns the first error found in results, ornullif all succeededfindPipelineErrors()- Returns array of all errors found, or empty array if all succeeded
const pipeline = conn.pipeline();
pipeline.select(512, 0, 10, 0, 'eq', [1]);
pipeline.select(512, 0, 10, 0, 'eq', [2]);
pipeline.update('metadata', 'primary', ['counter'], [['+', 'value', 1]]);
const pipelineResponse = await pipeline.exec();
// Access individual results
const [selectErr1, selectRes1] = pipelineResponse[0];
const [selectErr2, selectRes2] = pipelineResponse[1];
const [updateErr, updateRes] = pipelineResponse[2];
// Find errors easily
const firstError = pipelineResponse.findPipelineError();
if (firstError) {
console.error('First error:', firstError);
}
const allErrors = pipelineResponse.findPipelineErrors();
if (allErrors.length > 0) {
console.error('All errors:', allErrors);
}Converts UUID string to Tarantool-compatible format.
Parameters:
uuid(string) - UUID string (e.g.,'550e8400-e29b-41d4-a716-446655440000')
Returns: Encoded buffer for use in queries.
Note: Without conversion, UUIDs are sent as plain strings.
const uuid = conn.packUuid('550e8400-e29b-41d4-a716-446655440000');
const result = await conn.select('users', 'id', 1, 0, 'eq', [uuid]);Converts JavaScript number to Tarantool Decimal type.
Parameters:
number(number|bigint) - Number to convert
Returns: Encoded buffer for use in queries.
Note: Without conversion, large numbers are sent as Double/Integer.
const decimal = conn.packDecimal(123.456);
await conn.insert('prices', [1, 'Item', decimal]);Safely converts numbers to Tarantool integer format (up to int64).
Parameters:
number(number) - Number to convert
Returns: Encoded buffer for use in queries.
Note: Without conversion, numbers > int32 are encoded as Double.
const bigInt = conn.packInteger(9223372036854775807); // Max int64
await conn.insert('bigdata', [1, bigInt]);Converts value to Tarantool Interval type.
Parameters:
value(Object|number) - Interval specification
Returns: Encoded buffer for use in queries.
const interval = conn.packInterval({ years: 1, months: 2, days: 3 });Fetches and caches database schema (spaces and indexes).
Returns: Promise resolving to namespace object with space/index metadata.
Use case: Required if using space/index by name instead of ID without prefetchSchema: true.
await conn.fetchSchema();
const userId = conn.namespace['users'].id;Enable debug logging by setting the DEBUG environment variable:
DEBUG=tarantool-driver:* node app.jsThis displays detailed information about:
- Connection state changes
- Sent requests and received responses
- Buffer operations
- Schema fetching
- Event loop handling
-
📖 Performance Guide — Tips and tricks for maximum throughput 🚀
- Buffer size tuning
- Auto-pipelining optimization
- Unix socket advantages
-
📊 Benchmarks — Performance measurements and comparisons
- Read/write throughput comparisons
- Impact of different options
-
📋 Changelog — Version history and breaking changes
- New features by version
- Migration guides
Contributions are welcome! If you have questions or suggestions:
- Check existing issues
- Create a new issue with details
- Submit pull requests for bug fixes or features
For urgent matters, email directly: newbiecraft@gmail.com
Made with ❤️ for Tarantool community