Elide ships three built-in database drivers, each exposed as a synthetic ESM
module under the elide: scheme:
| Module | Import | Driver | Connection style |
|---|---|---|---|
elide:sqlite | import { Database } from "elide:sqlite" | SQLite 3 (JDBC, embedded) | Synchronous; new Database(path?) |
elide:postgres | import { Database } from "elide:postgres" | PostgreSQL (JDBC + HikariCP pool) | Asynchronous; await Database.connect(config) |
elide:mysql | import { Database } from "elide:mysql" | MySQL (JDBC + HikariCP pool) | Asynchronous; await Database.connect(config) |
There is no Elide.db global and no Elide.db.connect(); each driver is its
own module, imported by name. MongoDB and Redis are not supported, and there
is no ORM or query builder — these modules execute SQL directly.
Each module is registered lazily via ModuleRegistry.deferred(...) and resolves
only when imported; importing a module does not pollute the global scope.
elide:sqlite
SQLite is fully synchronous and embedded — there is no connection pool and no
network. You construct a Database directly.
Source:
dev.elide.lang.javascript.sqlite.JsSqliteModule:SqliteDatabaseConstructor, interfacedev.elide.db.sqlite3.SqliteDatabase, statement interfacedev.elide.db.sqlite3.SqliteStatement.
Constructor
new Database() // in-memory database
new Database(":memory:") // in-memory database (explicit)
new Database("") // in-memory database (empty string)
new Database("./data.db") // file-backed database
new Database("./data.db", opts) // file-backed with options
The second argument is an options object (file-backed databases only):
| Option | Type | Default | Effect |
|---|---|---|---|
create | boolean | false | Create the file if it does not exist (parent directory must be writable). |
readonly | boolean | false | Open the database read-only. |
If a path is given that does not exist and create is not true, the
constructor throws FileNotFoundException.
Database methods
| Method | Signature | Returns |
|---|---|---|
query | query(sql, ...args) | Statement |
prepare | prepare(sql, ...args) | Statement |
exec | exec(sql, ...args) | undefined (runs without returning rows) |
transaction | transaction(fn) | Transaction (a callable wrapper) |
loadExtension | loadExtension(name) | loads a SQLite extension |
serialize | serialize(schema?) | Uint8Array snapshot of the database |
close | close(throwOnError?) | closes the database |
query and prepare both return a Statement. The difference is intent:
query is for one-off execution, prepare for reuse. The statement is
prepared eagerly when arguments are passed.
Statement methods
| Method | Signature | Returns |
|---|---|---|
all | all(...args) | array of row objects |
values | values(...args) | array of value arrays (one per row) |
get | get(...args) | single row object, or undefined if none |
run | run(...args) | executes the statement, returns nothing |
Rows are returned as objects keyed by column name.
Example
import { Database } from "elide:sqlite";
const db = new Database(); // in-memory
db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
db.exec("INSERT INTO users (name) VALUES (?)", "Ada");
db.exec("INSERT INTO users (name) VALUES (?)", "Linus");
const all = db.query("SELECT * FROM users").all();
// → [ { id: 1, name: "Ada" }, { id: 2, name: "Linus" } ]
const one = db.query("SELECT name FROM users WHERE id = ?", 1).get();
// → { name: "Ada" }
db.close();
Transactions wrap a function; the returned wrapper is invoked to run the
function inside BEGIN / COMMIT (rolling back on a thrown error):
const insertAll = db.transaction((names) => {
for (const name of names) db.exec("INSERT INTO users (name) VALUES (?)", name);
});
insertAll(["Grace", "Margaret"]);
elide:postgres and elide:mysql
PostgreSQL and MySQL share an identical JavaScript surface — only the import
name, default port, and SQL dialect differ. Both connect over a pooled JDBC
connection (HikariCP) and expose async methods that return Promises.
Sources:
dev.elide.lang.javascript.postgresql.JsPostgresModule,dev.elide.lang.javascript.mysql.JsMysqlModule,dev.elide.db.postgresql.PostgresDatabase,dev.elide.db.mysql.MysqlDatabase, configdev.elide.db.jdbc.JdbcConnectionConfig.
Database.connect(config | url)
Database is a factory object with a single static method, connect, which
returns a Promise resolving to a database instance. It accepts either a
configuration object or a connection URL string.
await Database.connect({
host: "localhost", // optional, default "localhost"
port: 5432, // optional, default 5432 (postgres) / 3306 (mysql)
database: "myapp", // required
user: "postgres", // required
password: "secret", // required
pool: { /* PoolConfig */ },
ssl: { /* SslConfig */ },
properties: { /* extra JDBC props */ },
});
// Or a URL:
await Database.connect("postgresql://postgres:secret@localhost:5432/myapp");
await Database.connect("mysql://root:secret@localhost:3306/myapp");
database, user, and password are required when passing a config object;
omitting any throws a TypeError.
pool (optional)
| Field | Type | Default |
|---|---|---|
minSize | number | 2 |
maxSize | number | 10 |
connectionTimeout | number (ms) | 5000 |
idleTimeout | number (ms) | 30000 |
maxLifetime | number (ms) | 1800000 |
leakDetectionThreshold | number (ms) | 0 (disabled) |
ssl (optional)
| Field | Type | Default |
|---|---|---|
enabled | boolean | false |
rejectUnauthorized | boolean | true |
ca | string (path) | — |
cert | string (path) | — |
key | string (path) | — |
Database instance
| Member | Signature | Returns |
|---|---|---|
connected | property | boolean — whether the pool is active |
poolStats | property | pool statistics object |
query | query(sql, ...args) | a lazy query (.all() / .get() / .values()) |
exec | exec(sql, ...args) | Promise<ExecResult> |
prepare | prepare(sql) | Promise<Statement> |
transaction | transaction(fn) | Promise<T> — runs fn(tx) in a transaction |
batch | batch([[sql, args], ...]) | Promise<ExecResult[]> |
close | close() | Promise<void> |
query returns synchronously a lazy result object; the SQL is not executed
until you call one of its consuming methods:
| Method | Returns |
|---|---|
all() | Promise<Row[]> — all rows as objects keyed by column |
get() | Promise<Row | null> — the first row, or null |
values() | Promise<any[][]> — rows as positional value arrays |
ExecResult carries affectedRows (number), insertId (number | null), and
insertIds (number[]).
Parameter placeholders
PostgreSQL uses positional $1, $2, … placeholders (these must be sequential,
no gaps or repeats). MySQL uses ? placeholders. In both cases, bind values are
passed as trailing arguments to query / exec.
Example (PostgreSQL)
import { Database } from "elide:postgres";
const db = await Database.connect({
database: "myapp",
user: "postgres",
password: "secret",
});
// Read
const users = await db.query("SELECT * FROM users WHERE active = $1", true).all();
// Single row
const user = await db.query("SELECT * FROM users WHERE id = $1", 42).get();
// Write
const res = await db.exec("INSERT INTO users (name) VALUES ($1)", "Ada");
res.affectedRows; // → 1
res.insertId; // → generated key (or null)
// Transaction
await db.transaction(async (tx) => {
await tx.exec("UPDATE accounts SET balance = balance - $1 WHERE id = $2", 100, 1);
await tx.exec("UPDATE accounts SET balance = balance + $1 WHERE id = $2", 100, 2);
});
await db.close();
Example (MySQL)
import { Database } from "elide:mysql";
const db = await Database.connect({
database: "myapp",
user: "root",
password: "secret",
});
const rows = await db.query("SELECT * FROM users WHERE name = ?", "Ada").all();
await db.exec("INSERT INTO users (name) VALUES (?)", "Linus");
await db.close();
Prepared statements
const stmt = await db.prepare("INSERT INTO logs (msg) VALUES ($1)");
await stmt.exec("started");
await stmt.exec("stopped");
await stmt.close();
A prepared Statement exposes query(...args), exec(...args),
executeBatch(argsList), and close().
Transactions
The callback passed to transaction receives a Transaction object. It is
committed when the callback resolves and rolled back if it throws (or its
returned Promise rejects). The transaction object exposes:
| Member | Description |
|---|---|
isolation | current isolation level (READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE) |
active | whether the transaction is still open |
query(sql, ...args) / exec(sql, ...args) | run statements in the transaction |
commit() / rollback() | settle the transaction explicitly |
savepoint(name) / rollbackTo(name) | nested savepoints |
The default isolation level is READ_COMMITTED.
Notes
- SQLite is synchronous; PostgreSQL and MySQL are asynchronous (Promise-based).
- Connection pooling (PostgreSQL/MySQL) is provided by HikariCP and configured
via the
pooloption. - Plain JavaScript objects cannot be bound as SQL parameters — use primitives, strings, byte arrays, or arrays.
See also
- SQLite upstream: https://www.sqlite.org/docs.html
- PostgreSQL upstream: https://www.postgresql.org/docs/
- MySQL upstream: https://dev.mysql.com/doc/