mariadb

Non-blocking MariaDB and MySQL client for Node.js with promise and callback APIs, built for high-throughput production workloads.

Library
npm
v3.5.4
412stars
LGPL-2.1-or-later

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
89/100Excellent
Development Activity96
Maintenance96
Community84
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
83/100Excellent
Architecture88
Code Quality90
Innovation72
Learning Curve80

mariadb is the official MariaDB Corporation-maintained Node.js connector for MariaDB and MySQL servers. Written entirely in JavaScript with first-class TypeScript definitions, it implements the MySQL/MariaDB binary wire protocol directly rather than wrapping a native driver, giving it full control over connection lifecycle, packet encoding, and streaming behavior.

Beyond basic query execution, it offers features many general MySQL clients lack out of the box: readable-stream-based INSERT streaming for large payloads without buffering everything in memory, command pipelining that sends queries back-to-back without waiting for each response, bulk/batch insert APIs, connection pooling and pool clustering, prepared-statement caching, and ed25519 plugin authentication support. It requires Node.js 20 or later as of 3.5.3 and ships both promise (default) and callback entry points for compatibility with legacy driver-style code.

What You Get

  • Promise-based API by default (require('mariadb')) plus a dedicated callback API (require('mariadb/callback')) for drop-in compatibility with older driver code
  • Connection pooling via createPool() with automatic idle-connection management, and pool clustering via createPoolCluster() for multi-host failover/load balancing
  • Insert streaming: pass a Node.js Readable stream directly as a query parameter and the driver streams it to the server without buffering the full payload in memory
  • Command pipelining that sends successive commands to the server without waiting for each result, reducing round-trip latency for sequences of statements
  • Bulk/batch insert API for sending large numbers of rows in as few round trips as possible
  • Prepared-statement caching (LRU) to avoid re-preparing identical queries, plus binary protocol execute() alongside text-protocol query()
  • Zero-configuration SSL/TLS support and ed25519 plugin authentication
  • First-class TypeScript type definitions (.d.ts/.d.cts) shipped alongside both ESM and CJS builds

Common Use Cases

  • Backend API servers - Express/Fastify/Nest-style Node.js services querying a MariaDB or MySQL database with pooled connections for concurrent request handling
  • Bulk data ingestion pipelines - ETL-style scripts using the batch/bulk insert API to load large CSV/JSON datasets into MariaDB with minimal round trips
  • Streaming large payloads into BLOB/TEXT columns - applications that pipe file or HTTP-response streams directly into INSERT statements without loading them fully into memory
  • Multi-host/high-availability deployments - services using createPoolCluster() to spread load or fail over across multiple MariaDB replicas
  • Migrating off mysql/mysql2 - teams switching from older MySQL-only clients to gain MariaDB-specific features while keeping a similar promise/callback API surface

Under The Hood

Architecture The connector is organized around a Connection class (lib/connection.js) that owns socket I/O, send/receive command queues, and protocol state, wrapped by thin ConnectionPromise/ConnectionCallback facades (lib/connection-promise.js, lib/connection-callback.js) that adapt the same underlying connection to promise- or callback-style call sites. Pooling is layered on top via Pool/PoolPromise (lib/pool.js, lib/pool-promise.js), which manage idle/active connection sets, lazy connection creation up to connectionLimit, and request queuing when the pool is saturated; Cluster (lib/cluster.js) composes multiple named pools for multi-host failover. Protocol concerns are cleanly separated into lib/io/ (packet input/output streams, including a dedicated compression stream pair), lib/cmd/ (one command class per MySQL protocol command - query, prepare, execute, batch-bulk, change-user, etc. - plus lib/cmd/encoder and lib/cmd/decoder for binary/text row encoding), and lib/config/ (option classes for connections, pools, and clusters). This gives each protocol command a small, testable unit rather than one large monolithic client class, and it’s what makes features like insert streaming and pipelining possible without protocol-level hacks.

Tech Stack The package is pure JavaScript (ESM type: module) with a CJS build produced via esbuild (dist/promise.cjs, dist/callback.cjs) so both import and require consumers get supported entry points, each with matching .d.ts/.d.cts TypeScript definitions generated by a custom tools/generate-cts.js script. Runtime dependencies are deliberately minimal: denque for efficient queue structures, iconv-lite for character-set conversion, lru-cache for prepared-statement caching, and @types/geojson/@types/node for typing spatial and Node APIs. It requires Node.js >= 20. Build/test tooling includes esbuild, TypeScript, ESLint (with eslint-plugin-security), Prettier, and Vitest.

Code Quality The project has an extensive integration test suite (test/integration, dozens of files covering batch inserts, auth plugins, compression, cluster failover, prepared statements, datatypes, and more) plus a separate unit-test suite (test/unit) covering packet streams, command queues, and config parsing - run via Vitest with coverage collected through nyc/Codecov. CI (.github/workflows/ci.yml) gates every push/PR behind a fast lint stage (ESLint including eslint-plugin-security, Prettier, and full TypeScript tsc checks against the shipped .d.ts/.d.cts files) before running the test matrix, plus a separate CodeQL workflow. Error handling is centralized in lib/misc/errors.js, which raises typed, code-tagged errors (e.g. ER_WRONG_AUTO_TIMEZONE) rather than swallowing failures, and the codebase uses modern private class fields (#idleConnections, #closed) to enforce encapsulation in classes like Pool.

API Design The public API is intentionally small and symmetrical: createConnection, createPool, createPoolCluster, and importFile cover the vast majority of use cases, with query()/execute()/batch() as the core data methods on a connection. Promise and callback variants are exposed as separate module entry points (mariadb vs mariadb/callback) rather than a single dual-mode API, keeping each surface simple and its TypeScript types unambiguous. Getting started requires no boilerplate beyond createPool(options) plus await pool.getConnection() - documented directly in the README with a complete working example - and connection/pool option objects are validated up front through dedicated ConnectionOptions/PoolOptions classes, which produce clear errors early rather than surfacing failures deep in a query call.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search