Quick Start
Get up and running with Stabilize ORM in under 5 minutes
One API covers five databases. Set type and supply the connection string that driver expects:
import { DBType, type DBConfig } from "stabilize-orm";
// Pick one. The rest of your application does not change.const dbConfig: DBConfig = { type: DBType.SQLite, connectionString: "./data/app.db",};
// PostgreSQL// type: DBType.Postgres,// connectionString: "postgres://user:pass@localhost:5432/mydb",
// MySQL / MariaDB// type: DBType.MySQL,// connectionString: "mysql://user:pass@localhost:3306/mydb",
// SQL Server -- note the comma between host and port// type: DBType.MSSQL,// connectionString:// "Server=localhost,1433;Database=mydb;User Id=sa;Password=Your_password123;TrustServerCertificate=true",
// MongoDB -- the driver is optional, and writes need a replica set// type: DBType.MongoDB,// connectionString:// "mongodb://localhost:27017/mydb?directConnection=true&replicaSet=rs0",
export default dbConfig;- SQLite needs no server — the driver is built into the runtime (
bun:sqliteornode:sqlite) and the file is created if it does not exist. - PostgreSQL takes a
postgres://URL, MySQL and MariaDB amysql://one. - SQL Server takes an ADO-style string, where the host and port are separated by a comma — not a colon — and
TrustServerCertificate=trueis needed for the self-signed certificate a local container serves. Its pool connects on the first query rather than at construction, so a bad string surfaces then.
Every dialect accepts the optional retryAttempts and retryDelay shown in Retry and Pooling. For the SQL Server specifics — MERGE upserts, IDENTITY keys, OUTPUT INSERTED.* — see SQL Server.
import { defineModel, DataTypes } from "stabilize-orm";
const User = defineModel({ tableName: "users", timestamps: { createdAt: "createdAt", updatedAt: "updatedAt" }, columns: { id: { type: DataTypes.STRING, required: true, unique: true }, email: { type: DataTypes.STRING, length: 255, required: true, unique: true }, name: { type: DataTypes.STRING, length: 100, required: true }, isActive: { type: DataTypes.BOOLEAN, defaultValue: true }, deletedAt: { type: DataTypes.DATETIME, softDelete: true }, },});
export { User };The id here is a STRING, so it is supplied by the caller rather than generated — step 5 fills it with generateUUID(). That choice is deliberate: it behaves identically on all five databases. An INTEGER id is instead generated by the database and must be omitted from the payload. On SQL Server that means an IDENTITY column, which rejects an explicit value, and on MongoDB a counter document — see SQL Server. Either works on every backend; just be consistent about who assigns the key.
import { Stabilize, type CacheConfig, type LoggerConfig, LogLevel } from "stabilize-orm";import dbConfig from "../config/database";
const cacheConfig: CacheConfig = { enabled: false, ttl: 60,};
const loggerConfig: LoggerConfig = { level: LogLevel.Info, filePath: "logs/stabilize.log", maxFileSize: 5 * 1024 * 1024, maxFiles: 3,};
export const orm = new Stabilize(dbConfig, cacheConfig, loggerConfig);import { orm } from "../db";import { User } from "../models/User";import { generateUUID } from "stabilize-orm";
const userRepo = orm.getRepository(User);
// Create a new userconst newUser = await userRepo.create({ id: generateUUID(), email: "alice@example.com", name: "Alice Johnson",});console.log("Created:", newUser);
// Find by IDconst found = await userRepo.findOne(newUser.id);
// Updateconst updated = await userRepo.update(newUser.id, { name: "Alice Smith" });
// Delete (soft delete if deletedAt column exists)await userRepo.delete(newUser.id);
// Find allconst allUsers = await userRepo.find().execute(orm.client);