← All @molecule/* packages · App templates
@molecule/api-database-mysqlProvider bond · database · API (Node) · v1.0.2 · Apache-2.0
MySQL database provider for molecule.dev
npm install @molecule/api-database-mysqlnpm · Source on GitHub · Implements @molecule/api-database
@molecule/api-database-mysql is a provider bond on the API (Node) side: it implements the database core interface (@molecule/api-database) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
Works with: @molecule/api-bond, @molecule/api-database, @molecule/api-secrets
Secrets: MYSQL_URL
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
MySQL database provider for molecule.dev.
provider
npm install @molecule/api-database-mysql @molecule/api-bond @molecule/api-database @molecule/api-secrets mysql2
DatabaseConfigDatabase connection options (host, port, credentials, pool size, timeouts, SSL).
interface DatabaseConfig {
/**
* Database host.
*/
host?: string
/**
* Database port.
*/
port?: number
/**
* Database name.
*/
database?: string
/**
* Database user.
*/
user?: string
/**
* Database password.
*/
password?: string
/**
* Connection string (alternative to individual fields).
*/
connectionString?: string
/**
* Maximum number of connections in the pool.
*/
max?: number
/**
* Minimum number of connections in the pool.
*/
min?: number
/**
* Connection timeout in milliseconds.
*/
connectionTimeoutMillis?: number
/**
* Idle timeout in milliseconds.
*/
idleTimeoutMillis?: number
/**
* Enable SSL.
*/
ssl?:
| boolean
| {
rejectUnauthorized?: boolean
ca?: string
key?: string
cert?: string
}
}
DatabaseConnectionDatabase connection interface.
interface DatabaseConnection {
/**
* Executes a parameterized query.
*
* @param text - SQL query text with placeholders ($1, $2, etc.)
* @param values - Parameter values
*/
query<T = Record<string, unknown>>(text: string, values?: unknown[]): Promise<QueryResult<T>>
/**
* Releases the connection back to the pool.
*/
release(): void
}
DatabasePoolDatabase pool interface.
All database providers must implement this interface.
interface DatabasePool {
/**
* Executes a parameterized query using a pool connection.
*
* @param text - SQL query text with placeholders ($1, $2, etc.)
* @param values - Parameter values
*/
query<T = Record<string, unknown>>(text: string, values?: unknown[]): Promise<QueryResult<T>>
/**
* Acquires a connection from the pool.
*/
connect(): Promise<DatabaseConnection>
/**
* Begins a transaction.
*/
transaction?(): Promise<DatabaseTransaction>
/**
* Closes all connections in the pool.
*/
end(): Promise<void>
/**
* Returns pool statistics (optional).
*/
stats?(): {
total: number
idle: number
waiting: number
}
}
DatabaseTransactionDatabase transaction with commit and rollback (extends DatabaseConnection).
interface DatabaseTransaction extends DatabaseConnection {
/**
* Commits the transaction.
*/
commit(): Promise<void>
/**
* Rolls back the transaction.
*/
rollback(): Promise<void>
}
Poolinterface Pool extends Connection {
getConnection(): Promise<PoolConnection>
releaseConnection(connection: PoolConnection): void
on(event: 'connection', listener: (connection: PoolConnection) => any): this
on(event: 'acquire', listener: (connection: PoolConnection) => any): this
on(event: 'release', listener: (connection: PoolConnection) => any): this
on(event: 'enqueue', listener: () => any): this
end(): Promise<void>
pool: CorePool
}
PoolOptionsinterface PoolOptions extends ConnectionOptions {
/**
* Determines the pool's action when no connections are available and the limit has been reached. If true, the pool will queue
* the connection request and call it when one becomes available. If false, the pool will immediately call back with an error.
* (Default: true)
*/
waitForConnections?: boolean
/**
* The maximum number of connections to create at once. (Default: 10)
*/
connectionLimit?: number
/**
* The maximum number of idle connections. (Default: same as `connectionLimit`)
*/
maxIdle?: number
/**
* The idle connections timeout, in milliseconds. (Default: 60000)
*/
idleTimeout?: number
/**
* The maximum number of connection requests the pool will queue before returning an error from getConnection. If set to 0, there
* is no limit to the number of queued connection requests. (Default: 0)
*/
queueLimit?: number
/**
* Whether to reset the connection state (user variables, temporary tables, transactions, etc.) when
* releasing the connection back to the pool. This ensures each connection starts clean for the next user.
* Requires MySQL 5.7.3+. (Default: false)
*/
resetOnRelease?: boolean
}
QueryResultQuery result with rows and metadata.
interface QueryResult<T = Record<string, unknown>> {
/**
* Array of rows returned by the query.
*/
rows: T[]
/**
* Number of rows affected (for INSERT, UPDATE, DELETE).
*/
rowCount: number | null
/**
* Column metadata (optional, provider-dependent).
*/
fields?: Array<{
name: string
dataTypeID?: number
}>
}
ResultSetHeaderdeclare interface ResultSetHeader {
constructor: {
name: 'ResultSetHeader'
}
affectedRows: number
fieldCount: number
info: string
insertId: number
serverStatus: number
warningStatus: number
/**
* @deprecated
* `changedRows` is deprecated and might be removed in the future major release. Please use `affectedRows` property instead.
*/
changedRows: number
}
RowDataPacketdeclare interface RowDataPacket {
constructor: {
name: 'RowDataPacket'
}
[column: string]: any
[column: number]: any
}
PoolConnectioncreateMigrator(migrationsDir)Returns a runMigrations() bound to a migrations directory.
function createMigrator(migrationsDir: string): () => Promise<void>
migrationsDir — Absolute path to the directory of ordered *.sql migration files. Resolve via join(new URL('.', import.meta.url).pathname, '../../migrations') from the app's scripts/migrate.ts.Returns: A no-arg runMigrations() that creates the database (if missing) and applies every migration file in lexical order using a multi-statement connection.
createPool(config)Creates a MySQL database pool that implements the DatabasePool interface.
Reads MYSQL_URL, MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER,
and MYSQL_PASSWORD from env if not provided in config.
function createPool(config?: DatabaseConfig): DatabasePool
config — Database connection configuration.Returns: A DatabasePool backed by a MySQL connection pool.
createStore(pool)Creates a DataStore backed by a MySQL DatabasePool.
function createStore(pool: DatabasePool): DataStore
pool — The MySQL DatabasePool to use for queries.Returns: A DataStore that translates CRUD operations to MySQL-compatible SQL.
databaseMysqlSecretDefinitionsSecret definitions required by the MySQL database bond.
const databaseMysqlSecretDefinitions: SecretDefinition[]
poolThe default MySQL pool instance, created with env-based configuration on first use.
const pool: DatabasePool
storeThe MySQL-backed DataStore singleton over the default pool. Wired at startup
via setStore(store) from @molecule/api-database, mirroring the
postgresql/sqlite bonds so the injector's setter/provider pairing
(setStore → store) finds it.
const store: DataStore
Implements @molecule/api-database interface.
Setup function to register this provider with the core interface:
import { setPool, setStore } from '@molecule/api-database'
import { pool, store } from '@molecule/api-database-mysql'
export function setupDatabaseMysql(): void {
setPool(pool)
setStore(store)
}
Peer dependencies:
@molecule/api-bond ^1.0.1@molecule/api-database ^1.0.1@molecule/api-secrets ^1.0.1MYSQL_URL (required) — MySQL connection URL
mysql://user:pass@localhost:3306/myapp@molecule/api-bond
@molecule/api-database
@molecule/api-secrets
mysql2
Connection config is required, one way or another. Set MYSQL_URL, OR the
discrete MYSQL_HOST/MYSQL_PORT/MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD
vars, OR pass an explicit config object to createPool(). With NONE of those,
createPool() now throws an actionable "MYSQL_URL is not set" error at first use
instead of silently connecting as root@localhost with no password and failing
later with a raw ECONNREFUSED/ER_ACCESS_DENIED.
pool.stats is undefined — mysql2 exposes no public stats API. Call it as
pool.stats?.() (the DatabasePool interface already marks it optional); a
fabricated { total: 0, idle: 0, waiting: 0 } would read as "pool down" to a
health page even on a perfectly healthy connection. Only the postgresql bond
returns real counts.
like is case-insensitive and does NOT escape the value — the caller's own
%/_ are honored as wildcards, identical to the postgresql/sqlite bonds. For
human-typed search input, use ilike instead (escapes + auto-wraps %…%) — see
WhereCondition['operator'] in @molecule/api-database.
A migration file with a genuine error (not an idempotent "already exists") now FAILS the boot with every broken file named, instead of warn-logging and booting with a partial schema.