outlet-orm is an Active Record ORM for Node.js 18+ that covers much more than the usual SQL layer. The package bundles a relational ORM core, a schema builder and migration engine, seeders, backup and reverse-engineering tools, a REST/GraphQL API layer, a multi-provider AI bridge, and an MCP server for agents.
The public entry point is src/index.js. TypeScript signatures are published through types/index.d.ts. The real surface is also confirmed by the test suites in tests and the examples in examples.
- Positioning
- Installation
- Quick Start
- Active Record Model
- Queries and QueryBuilder
- Relationships and Eager Loading
- Advanced Model Features
- DatabaseConnection and Standalone Mode
- Schema Builder, Migrations, and Seeders
- Backups, Restore, and Migration Safety
- Reverse Engineering, Init, and Conversion
- Advanced SQL Objects and Transactions
- HTTP / GraphQL API Layer
- API Spec Import and Diff
- AI, MCP, and Automation
- CLI Reference
- TypeScript
- Examples and Validation
- Useful Notes and Limits
outlet-orm is not just a CRUD ORM. The package spans 8 complementary areas:
| Area | Main exports / commands | What it provides |
|---|---|---|
| SQL ORM | Model, QueryBuilder, DatabaseConnection |
Active Record, fluent queries, transactions, casts, validation |
| Relationships | hasOne, hasMany, belongsTo, belongsToMany, hasManyThrough, hasOneThrough, morph* |
Relational navigation and eager loading |
| Schema / migrations | Schema, Blueprint, Migration, MigrationManager, Seeder, SeederManager |
Schema evolution, seeders, deployment workflows |
| DB objects | View, Trigger, Procedure, Function, Transaction, useSchema |
Views, triggers, procedures, savepoints, isolation levels |
| Backups | BackupManager, BackupScheduler, BackupEncryption, BackupSocketServer, BackupSocketClient |
SQL/JSON backups, encryption, scheduling, restore |
| API Layer | Api, ApiGraphQL, ApiAdapter, MockAdapter, cache, offline, realtime |
The same modeling style, but over HTTP |
| AI bridge | AIManager, Ai, providers, TextBuilder, AIQueryBuilder, AISeeder, AIPromptEnhancer |
Chat, tools, NL->SQL, AI seeds, guided generation |
| CLI / MCP | outlet, outlet-migrate, outlet-reverse, outlet-mcp, outlet api import, outlet api diff |
Project init, conversion, reverse engineering, MCP agent integration |
Base installation:
npm install outlet-ormThen install only the driver you need:
npm install mysql2npm install pgnpm install sqlite3Useful dependencies and prerequisites:
- Node.js
>= 18.0.0 - the main package is CommonJS (
require/module.exports) mysql2,pg, andsqlite3are optional peer dependencies loaded on demandgraphql-wsis optional if you use GraphQL subscriptions- the package ships its own types through
types/index.d.ts
const { DatabaseConnection } = require('outlet-orm');
const db = new DatabaseConnection({
driver: 'sqlite',
database: ':memory:'
});
await db.connect();The core layer supports these drivers:
mysqlpostgres/postgresqlsqlite
Configuration can come from:
new DatabaseConnection({...})directly.env(DB_DRIVER,DB_HOST,DB_DATABASE,DB_FILE,DATABASE_URL, and others)database/config.jsfor the migration CLI
const { Model } = require('outlet-orm');
class User extends Model {
static table = 'users';
static fillable = ['name', 'email', 'password', 'status'];
static hidden = ['password'];
static casts = {
id: 'int',
email_verified: 'boolean'
};
static connection = db;
}const user = await User.create({
name: 'Ada',
email: 'ada@example.com',
password: 'secret',
status: 'active'
});
const activeUsers = await User
.where('status', 'active')
.orderBy('id', 'desc')
.limit(10)
.get();The ORM core is built around src/Model.js. A model typically declares:
static tablestatic primaryKeystatic timestampsstatic fillablestatic hiddenstatic castsstatic appendsstatic connectionstatic softDeletesstatic rules
Main model capabilities:
- static CRUD:
all(),find(),findOrFail(),create(),insert(),update(),delete() - lookup helpers:
first(),firstOrCreate(),firstOrNew(),updateOrCreate(),upsert() - pagination:
paginate(page, perPage) - streaming:
cursor(chunkSize) - serialization:
toJSON(),only(),except() - lifecycle:
save(),destroy(),fresh(),refresh(),replicate() - change tracking:
getDirty(),isDirty(),wasChanged(),getChanges()
Useful detail: instances are wrapped in a Proxy, which enables property-style access:
const user = await User.find(1);
console.log(user.name);
user.name = 'Grace';
await user.save();This behavior is covered by tests/PropertyAccess.test.js.
QueryBuilder covers the standard cases plus a number of Laravel-style parity helpers.
Common methods:
select(...columns)columns([...])distinct()where(column, value)where(column, operator, value)orWhere(...)whereIn(),whereNotIn()whereNull(),whereNotNull()whereBetween(),whereNotBetween()whereLike()orderBy()limit(),offset(),skip(),take()groupBy()having(),havingRaw()join(),leftJoin(),rightJoin(),crossJoin()union(),unionAll()
with(...)withCount(...)withSum(relation, column)withAvg(relation, column)withMin(relation, column)withMax(relation, column)whereHas(relation, callback)has(relation, count)whereDoesntHave(relation)
get()first()firstOrFail()paginate()count()exists()/doesntExist()insert()/insertGetId()update()updateAndFetch()delete()increment()/decrement()
pluck(column)pluck(column, keyColumn)value(column)sum(),avg(),min(),max()chunk(size, callback)when(condition, callback, fallback)tap(callback)toSQL()dd()clone()
Example:
const rows = await User
.where('status', 'active')
.whereBetween('created_at', ['2026-01-01', '2026-12-31'])
.withCount('posts')
.withMax('posts', 'created_at')
.orderBy('posts_count', 'desc')
.get();Recent behaviors and parity helpers are covered by tests/NewParityFeatures.test.js, tests/NewFeatures.test.js, tests/NewEvolutions.test.js, and tests/QueryBuilderStandalone.test.js.
Relationships supported by the ORM core:
hasOnehasManybelongsTobelongsToManyhasManyThroughhasOneThroughmorphOnemorphManymorphTo
Example:
class User extends Model {
static table = 'users';
static connection = db;
posts() {
return this.hasMany(Post, 'user_id', 'id');
}
}
class Post extends Model {
static table = 'posts';
static connection = db;
author() {
return this.belongsTo(User, 'user_id', 'id');
}
}
const users = await User.with('posts').get();Additional capabilities:
- constrained eager loading
- nested eager loading through dot notation
withDefault()on relationshipsattach(),detach(),sync()onbelongsToMany- morph map support through
Model.setMorphMap(...)
Related test suites:
The package includes several behaviors that are not always present in lightweight ORMs.
static hiddenwithHidden()withoutHidden(show)makeVisible()makeHidden()static appends
Also demonstrated in examples/hidden-attributes-demo.js.
Supported cast types:
int/integerfloat/doublestringbool/booleanarrayjsondatedatetimetimestamp
The model layer also covers:
- accessors / mutators
- validation rules through
static rules validate()andvalidateOrFail()fillableguarding on insert / update
Supported events:
creating,createdupdating,updatedsaving,saveddeleting,deletedrestoring,restored
You can use:
Model.on(event, callback)- helper methods such as
creating(...),saved(...), and others Model.observe(MyObserver)- global scopes via
addGlobalScope()/withoutGlobalScope()/withoutGlobalScopes() - local scopes verified by tests/NewEvolutions.test.js
Soft-delete features:
static softDeletes = truestatic DELETED_ATwithTrashed()onlyTrashed()trashed()restore()forceDelete()
The schema builder also exposes softDeletes() to add deleted_at.
src/DatabaseConnection.js handles:
- connection and pooling
- query execution
- transactions
- query logging
- SQL aggregates
- standalone builder usage through
from(...)
Standalone example without a model:
await db.from('users')
.where('status', 'pending')
.update({ status: 'active' });
const exists = await db.from('users')
.where('email', 'ada@example.com')
.exists();Useful low-level functions:
select()insert()/insertMany()update()delete()count()aggregate()executeRawQuery()execute()increment()/decrement()
Query logging can be enabled globally:
DatabaseConnection.enableQueryLog();
// ...
const log = DatabaseConnection.getQueryLog();
DatabaseConnection.flushQueryLog();The journal backup flow relies on this mechanism.
The schema builder is provided by Schema and Blueprint.
schema.create(name, callback)schema.table(name, callback)schema.rename(from, to)schema.drop(name)schema.dropIfExists(name)schema.hasTable(name)schema.hasColumn(table, column)schema.hasIndex(table, indexName)/indexExists(...)
Blueprint notably covers:
- numeric, text, date, JSON, UUID, and binary columns
timestamps()with multiple overloadssoftDeletes()- indexes, unique indexes, full text
- foreign keys
- check constraints
Migration example:
const { Migration } = require('outlet-orm');
class CreateUsersTable extends Migration {
async up() {
const schema = this.getSchema();
await schema.create('users', (table) => {
table.id();
table.string('name');
table.string('email').unique();
table.timestamps();
table.softDeletes();
});
}
async down() {
await this.getSchema().dropIfExists('users');
}
}
module.exports = CreateUsersTable;The Migration base class also provides:
getSchema()query(table)/table(table)for a standaloneQueryBuilderinside migrationslog(),info(),warn()for structured loggingshouldRun()to skip a migrationwithinTransactionto wrapup()/down()in a transaction- data-preservation helpers:
transformData(),backupData(),restoreData()
MigrationManager handles:
- installation of the migrations table
- execution of pending migrations
- rollback by batch
- reset / refresh / fresh
- non-interactive deploy for CI/CD
resolve --appliedandresolve --rolled-back- drift detection through checksums
- detection of migrations missing from disk
_migrationstracking columns:started_at,finished_at,rolled_back_at, and others- advisory locks for deploy / resolve on MySQL and PostgreSQL
The package provides:
SeederSeederManagermake:seedscaffoldingseed/db:seed- class targeting through
--seeder/--class
The backup subsystem is not a minor add-on: it is directly integrated into the destructive migration lifecycle.
- full
fullbackup - partial
partialbackup - query-log-based SQL journal
journal sqlorjsonformat- encryption through
BackupEncryption - scheduling through
BackupScheduler - command sockets through
BackupSocketServerandBackupSocketClient
Features built into the package:
- auto-backup before
fresh,reset,refresh, androllback - retention of auto-backups per command
- automated restore through
restore:auto - restore history
- production protection through
OUTLET_PRODUCTION_CONFIRM=1and explicit database-name confirmation --skip-auto-backupis ignored in production- normalized exit codes
These behaviors are verified by:
- tests/Backup.test.js
- tests/BackupEncryption.test.js
- tests/BackupSocket.test.js
- tests/MigrationDataPreservation.test.js
- tests/MigrationDeployOptions.test.js
- tests/MigrationExtraOptions.test.js
The package includes three complementary approaches to speed up adoption.
Purpose:
- quickly initialize an outlet-orm project
- generate folders, a
.env, a config file, migrations, and seeders - classic interactive mode
- AI prompt mode through
--prompt
Examples:
outlet-initoutlet-init --prompt "Blog with users, posts, comments" --driver sqlitePurpose:
- parse SQL
CREATE TABLE - infer JavaScript casts
- suggest
fillable,hidden, and relationships - detect pivot tables for
belongsToMany
Purpose:
- introspect an existing database or SQL dump
- generate schema-builder-based migrations
- generate seeders from existing data
Reverse engineering covers MySQL, PostgreSQL, and SQLite in the CREATE TABLE parser, including many types, defaults, and foreign keys. See tests/Reverse.test.js.
The package goes beyond tables.
Public exports:
ViewTriggerProcedureFunctionTransactionuseSchema(schemaOrDb)
Capabilities exposed through Schema and the related builders:
createView,createOrReplaceView,dropView,dropViewIfExists,hasView,getViewscreateTrigger,dropTrigger,dropTriggerIfExists,hasTrigger,getTriggerscreateProcedure,dropProcedure,dropProcedureIfExists,hasProcedurecreateFunction,dropFunction,dropFunctionIfExists,hasFunction
Example: examples/migrations/create_views_and_triggers.js.
DatabaseConnection and Transaction cover:
beginTransaction()commit()rollback()transaction(callback)afterCommit(callback)savepoint(name)rollbackTo(name)releaseSavepoint(name)setIsolationLevel(level)
Exported constants:
IsolationLevel.READ_UNCOMMITTEDIsolationLevel.READ_COMMITTEDIsolationLevel.REPEATABLE_READIsolationLevel.SERIALIZABLE
When a capability is not supported, the package exposes UnsupportedCapabilityError.
The API layer in src/Api reproduces a model-like experience, but over HTTP.
ApiApiModelApiAdaptercreateAdapter()ApiGraphQLMockAdapterInterceptorManagerApiCacheApiValidatorApiPaginatorApiQueryBuilder
- CRUD through
find,findOrFail,all,get,create,save,destroy - HTTP query builder with
where,orWhere,whereIn,whereNull,orderBy,limit,offset,with,select - page/cursor/offset pagination and async iteration
bearer,basic,apiKey,cookie,oauth2, anddynamicHeadersauth- request logs and
toRequest()for debugging without sending - upload with progress when
XMLHttpRequestis available - payload / response validation
- typed error hierarchy (
ApiError,ApiValidationError,ApiRateLimitError, and others)
The package also adds:
- cache strategies: cache-first, network-first, stale-while-revalidate, cache-only, network-only
- stores: memory, localStorage, sessionStorage
- offline queue through
MutationQueue - offline storage wrappers
- watchers / event stream / websocket
- a complete mock adapter for tests
- request / response interceptors, retry, and circuit breaker
Related suites are visible in:
- tests/ApiLayer.test.js
- tests/ApiLayerIntegration.test.js
- tests/ApiCache.test.js
- tests/ApiOffline.test.js
- tests/ApiInterceptors.test.js
- tests/ApiGraphQL.test.js
- tests/ApiValidation.test.js
- tests/ApiPagination.test.js
- tests/ApiMock.test.js
The package also provides a pipeline for generating API models from specs or reference documentation.
Targeted command for:
- OpenAPI / Swagger
- Postman Collection
- GraphQL introspection
- RAML
- API Blueprint
- extraction from reference documentation through
--doc
Notable options visible in bin/api/import.js:
--spec <path|url>--doc <path|url>--output <dir>--lang js|ts--auth bearer|basic|apiKey|oauth2--strategy tag|resource--format auto|openapi|postman|raml|apiblueprint|graphql--max-depth <n>--include-official-subdomains true|false--run-delta
The pipeline also handles execution artifacts such as snapshots, run deltas, and coverage diagnostics.
Compares an OpenAPI spec with a directory of generated models:
- detects missing models
- detects extra models
- compares endpoints
- compares
fillablefields
The AI layer covers two areas: general LLM integration and ORM-oriented automation.
AIManagerand its aliasAiAIFacadeTextBuilder- contracts:
ChatProviderContract,EmbeddingsProviderContract,ImageProviderContract,AudioProviderContract,ModelsProviderContract,ToolContract - providers:
OpenAIProvider,OllamaProvider,OllamaTurboProvider,ClaudeProvider,GeminiProvider,GrokProvider,MistralProvider,OnnProvider,CustomOpenAIProvider - support:
StreamChunk,Message,Document,ProviderError,ToolRegistry,ToolChatRunner,SystemInfoTool - domain components:
AIQueryBuilder,AISeeder,AIQueryOptimizer,AIPromptEnhancer - historical / utility components:
MCPServer,AISafetyGuardrails,PromptGenerator
- chat and text generation across multiple providers
- normalization for chat / embeddings / images / audio
- tool calling
- JSON schema validation
- protection for AI-related files and payloads
- NL->SQL through
AIQueryBuilder - SQL optimization suggestions through
AIQueryOptimizer - realistic data generation through
AISeeder - schema / model / migration generation through
AIPromptEnhancer - initial project / blueprint generation through
PromptGenerator
Reference suites:
outlet-mcp starts the MCP server on stdio.
Options:
--project,-p <path>--no-safety
Tools exposed by default in src/AI/MCPServer.js:
migrate_statusmigrate_runmigrate_rollbackmigrate_resetmigrate_makeseed_runschema_introspectquery_executemodel_listbackup_createbackup_restoreai_queryquery_optimize
Destructive actions are protected by consent guardrails when safety is enabled.
outlet <command> [args]Subcommands routed by bin/outlet.js:
| Command | Role |
|---|---|
outlet init |
initializes a project |
outlet convert |
converts SQL into models |
outlet migrate |
runs the migration manager |
outlet reverse |
reverse engineers a DB / SQL source |
outlet mcp |
starts the MCP server |
outlet api import |
imports API models from specs / docs |
outlet api diff |
compares a spec and generated models |
Historical aliases remain exposed through package.json:
outlet-initoutlet-convertoutlet-migrateoutlet-reverseoutlet-mcpoutlet-api-importoutlet-api-diff
Subcommands documented by the current implementation:
| Command | Role |
|---|---|
install |
creates only the migrations table |
migrate / up |
executes pending migrations |
deploy |
applies pending migrations without interaction, for CI/CD |
resolve --applied=<name> |
marks a migration as applied |
resolve --rolled-back=<name> |
marks a migration as rolled back |
rollback --steps=N |
rolls back one or more batches |
reset --yes |
full rollback |
refresh --yes |
reset + migrate |
fresh --yes |
drop all + migrate |
status |
migration status |
seed / db:seed |
executes seeders |
make <name> |
scaffolds a migration |
make:seed <name> |
scaffolds a seeder |
make:transform <name> |
scaffolds a data-transformation migration |
restore:auto [--backup=<file>] |
restores an auto-backup |
backups:list [--json] |
lists auto-backups |
Important flags:
--pretend--allow-failed--step--steps=N/-s N--batch=N--seed--seeder=Name/--class=Name--pending--create=<table>--table=<table>--skip-auto-backup--allow-drift--backup=<file>--json--yes/-y
Useful environment variables:
OUTLET_PRODUCTION_CONFIRM=1OUTLET_ALLOW_DRIFT=1
The package publishes declarations in types/index.d.ts. TypeScript examples live in:
Minimal example:
import { Model, DatabaseConnection } from 'outlet-orm';
const db = new DatabaseConnection({ driver: 'mysql', host: 'localhost', database: 'app' });
class User extends Model {
static readonly table = 'users';
static readonly connection = db;
}Practical note: the TypeScript declarations cover most of the public surface, but helpers introduced very recently on the JavaScript side may still need to be cross-checked in src/QueryBuilder.js and CHANGELOG.md if you are using the latest parity additions.
Useful reference points in the repository:
- examples/usage.js : CRUD, relationships, eager loading, pagination
- examples/hidden-attributes-demo.js :
hidden,withHidden,withoutHidden - examples/nested-demo.js : nested relationships
- examples/polymorphic-demo.js : polymorphic relationships
- examples/relations-usage.js : standard relationships
- examples/migrations : reference migrations
- examples/simplified-architecture : small reference architecture
- labo/run.js : lab scenario runner
- tests : the most reliable behavior map of the package
Repository validation commands:
npm test --silentnpm run test:labnpm run lint- The package is very broad: for a simple use case, start with
DatabaseConnection,Model,Schema,Migration, andSeeder. - SQL drivers are loaded lazily: a missing-driver error appears at connection time, not when the main package is installed.
- The migration CLI can read
database/config.js, but it also falls back to.envandDATABASE_URL. - The HTTP API layer is independent from the SQL layer: you can use one without the other.
- The AI layer is optional, but tightly integrated with ORM, CLI, and MCP workflows.
- Destructive operations are intentionally stricter in production.
- The changelog is dense and useful: CHANGELOG.md documents additions in detail by version, especially v13+ for the API layer, v14+ for advanced migrations, and v15+ for compatibility helpers.