ts-prorm-orm
v2.4.0
Published
A TypeScript ORM for MySQL, PostgreSQL, SQLite, MSSQL, and more
Maintainers
Readme
ts-prorm-orm
A TypeScript ORM supporting multiple database dialects with full TypeScript support.
Published on npm as
ts-prorm-orm—npm install ts-prorm-orm
Documentation: prod-orm.io — getting started · core concepts · guides · API reference · in the browser
Features
- Multi-database support: 27 SQL dialects. Core implementations for SQLite, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL, CockroachDB, Amazon Redshift, IBM Db2, Snowflake, ClickHouse, DuckDB, SAP HANA and Google Cloud Spanner; Postgres-derived support for TimescaleDB, Greenplum, YugabyteDB, Vertica, Trino, Exasol, CrateDB, QuestDB and Firebird; MySQL-derived for TiDB, SingleStore and Databricks; and Turso/libSQL on SQLite. See Supported Dialects for what is verified against a real engine.
- Relations without SQL:
hasOne/hasMany/belongsTo/belongsToManyvia methods or decorators, eager loading withinclude, andrequired/include.whereto filter parents by their children — applied beforeLIMIT, so pagination is correct - TypeScript-first: Full TypeScript support with decorators
- CRUD operations: Full query builder with associations, scopes, transactions
- Migrations: Database versioning and seeding
- Hooks: Lifecycle events for models
- Validation: Built-in and custom validators
- Stored Procedures: Create and call stored procedures (across supported dialects)
- Triggers: Database triggers with FOR EACH ROW and WHEN clauses (across supported dialects)
- Query logging: Sequelize-compatible
logging(false/true/ a(sql, timing)function), overridable per query, plusbenchmarkfor elapsed time andlogQueryParametersfor bound values. Every operation logs, not just some - Bulk writes:
increment/decrementdo the arithmetic in the database, so concurrent updates don't lose each other;bulkUpdatewrites different values to many rows in one statement instead of one round trip per row - Aggregates:
count,sum,avg,min,max— all issuing real SQL aggregates and honouringwhere, scopes, soft-deletes and relation filters;group+havingfor grouped results - Sequences:
createSequence()on PostgreSQL, MariaDB, Oracle, MSSQL, Db2 and friends. SQLite and MySQL have no sequences and report that explicitly rather than emitting SQL the driver rejects - Table Partitions: RANGE, LIST, HASH partitioning (across supported dialects)
- Partial Indexes: Conditional indexes for MySQL, MariaDB, PostgreSQL, Oracle, MSSQL
- Row-Level Security (RLS): PostgreSQL, Oracle VPD, MSSQL Security Policies
- Materialized Views: With FAST/COMPLETE refresh (PostgreSQL, Oracle)
- Views: Database views support
- Full-Text Search: one
createFullTextIndex()call resolves per dialect — GIN overto_tsvectoron PostgreSQL,FULLTEXTon MySQL/MariaDB, FTS5 on SQLite - JSON/JSONB: Native JSON data type support
- Spatial Data: PostGIS support for PostgreSQL
- Foreign Data Wrappers: PostgreSQL FDW support
- User Management: Database users and privileges (PostgreSQL, Oracle, MSSQL)
- Connection Pooling: Efficient connection pool management
- Query Optimization: Prepared statements, query hints, caching
- Audit Logging: Built-in audit trail functionality
- Polymorphic Associations: Built-in helpers for polymorphic relationships
- Self-referential Associations: Tree structure support
- Object, key-value and document stores: S3, MinIO, R2, GCS, Azure Blob, Redis,
MongoDB, DynamoDB, Cassandra, Elasticsearch and ~90 more ship as standalone
*Storeclasses with APIs matching each engine. These are not part of the model/relation layer — see NoSQL Stores
Installation
npm install ts-prorm-ormIn the browser
No build step required — one script tag, served from the documentation site:
<script src="https://prod-orm.io/cdn/prorm.min.js"></script>
<script>
const db = await prorm.openBrowserDatabase({ database: 'notes' });
const Note = db.define('Note', { title: prorm.DataTypes.STRING });
await db.sync();
await Note.create({ title: 'Hello' });
</script>The same models, finders and operators, against a real SQLite database in the
page — SQLite compiled to WebAssembly where Web SQL is gone, which is Chrome and
Firefox. localStorage, sessionStorage, cookies and adapters for PouchDB and
RxDB come with it. See the browser guide.
Quick Start
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'sqlite',
storage: ':memory:',
logging: console.log,
});
const User = prorm.define('User', {
name: DataTypes.STRING,
email: {
type: DataTypes.STRING,
validate: { isEmail: true },
},
});
await prorm.sync();
const user = await User.create({ name: 'John', email: '[email protected]' });
console.log(user.toJSON());Database type coverage
prorm spans 22 database types, each with at least 5 supported engines — 27
SQL dialects and 102 NoSQL/data stores (129 engines). Full taxonomy:
docs/database-types.md.
| Type | Engines | |------|---------| | Relational (OLTP) | SQLite, MySQL, PostgreSQL, MariaDB, Oracle, MSSQL, Db2, Firebird, Turso | | Warehouse / OLAP | ClickHouse, DuckDB, Redshift, Snowflake, Vertica, Greenplum, Exasol, HANA, Databricks, Trino | | NewSQL / distributed | CockroachDB, YugabyteDB, TiDB, SingleStore, Spanner | | Document | MongoDB, Couchbase, RethinkDB, SurrealDB, ArangoDB | | Key-value | Redis, Memcached, etcd, DynamoDB, Aerospike | | Wide-column | Cassandra, ScyllaDB, Keyspaces, HBase, Bigtable | | Graph | Neo4j, ArangoDB, TigerGraph, Neptune, Dgraph | | Vector | Pinecone, Milvus, Qdrant, Weaviate, Chroma | | Time-series | InfluxDB, TimescaleDB, QuestDB, Prometheus, VictoriaMetrics | | Search | Elasticsearch, OpenSearch, Meilisearch, Typesense, Solr | | Object storage | S3, GCS, Azure Blob, MinIO, Cloudflare R2 | | Streaming / queue | Kafka, NATS, RabbitMQ, Pulsar, Redpanda | | In-memory data grid | Hazelcast, Ignite, GridGain, Infinispan, Geode, Coherence | | Embedded storage engine | RocksDB, LevelDB, LMDB, UnQLite, NeDB, PouchDB | | Ledger / immutable | QLDB, immudb, BigchainDB, TerminusDB, Fluree, ProvenDB | | Multi-model | Cosmos DB, FaunaDB, OrientDB, MarkLogic, Firestore, RavenDB | | RDF / triplestore | Fuseki, GraphDB, Stardog, Blazegraph, Virtuoso, AllegroGraph | | Real-time OLAP | Druid, Pinot, StarRocks, Doris, Rockset, Materialize | | Cloud pub/sub | Kinesis, Event Hubs, Pub/Sub, SQS, SNS, EventStoreDB | | Edge / serverless KV | Cloudflare KV, Vercel KV, Upstash, Deno KV, Momento, DAX | | Job / task queue | Beanstalkd, Gearman, BullMQ, NSQ, Resque, Bee-Queue | | Log / observability | Loki, Splunk, Graylog, Sumo Logic, SigNoz, Papertrail |
Supported Dialects
How these are verified. SQLite and DuckDB are embedded, so the test suite runs
against the real engine on every commit. PostgreSQL, MySQL, MariaDB, MSSQL, Oracle,
CockroachDB and ClickHouse have real servers available via docker-compose.test.yml
and are exercised by npm run test:integration. The remaining dialects are covered
by unit tests against an in-memory SQL simulator, which checks generated SQL but not
engine behaviour. "Stable" below means the implementation is complete, not that it
has been run against that vendor's server in CI.
Dialects not listed in the table are implemented as subclasses of a core dialect and inherit its behaviour: TimescaleDB, Greenplum, YugabyteDB, Vertica, Trino, Exasol, CrateDB, QuestDB and Firebird extend PostgreSQL; TiDB, SingleStore and Databricks extend MySQL; Turso/libSQL extends SQLite.
| Dialect | Status | Features |
|---------|--------|-----------|
| SQLite | Stable | FTS5, CTEs, Window Functions, UPSERT |
| MySQL | Stable | Stored procedures, triggers, partitions |
| PostgreSQL | Stable | RLS, FDW, PostGIS, Sequences, Extensions |
| MariaDB | Stable | Stored procedures, triggers, virtual columns |
| Oracle | Stable | Sequences, stored procedures |
| MSSQL | Stable | Sequences, stored procedures, RLS |
| CockroachDB | Stable | Distributed SQL, Postgres wire protocol/driver (pg), horizontal scalability |
| Amazon Redshift | Stable | Postgres-derived cloud data warehouse (pg driver), DISTKEY/SORTKEY instead of indexes, no FK/unique enforcement |
| IBM Db2 | Stable | ibm_db driver, FETCH FIRST pagination, MERGE upsert |
| Snowflake | Stable | snowflake-sdk driver, VARIANT semi-structured type, warehouse-based compute, no traditional indexes |
| ClickHouse | Stable | @clickhouse/client driver, columnar OLAP, requires ENGINE clause on CREATE TABLE, no multi-statement transactions, no FK enforcement |
| DuckDB | Stable | duckdb driver, embedded/in-process OLAP (file or :memory:, no server), window functions, recursive CTEs, LIST/STRUCT/MAP types, direct Parquet/CSV/JSON table functions |
| SAP HANA | Stable | hdb driver, in-memory column-store tables, native UPSERT ... WITH PRIMARY KEY, LIMIT n OFFSET m pagination requiring a sentinel LIMIT |
| Google Cloud Spanner | Stable | @google-cloud/spanner driver (GoogleSQL), globally distributed with externally-consistent transactions, Mutation API for bulk/blind writes, INSERT OR UPDATE upsert syntax |
Extended dialects
Twelve additional dialects subclass the nearest wire-compatible base dialect and
override the grammar / type-mapping that genuinely differs, reusing the base's
driver. Each has a dedicated page under docs/dialects/ and
a connection-free SQL-generation test suite (tests/dialects/<name>*.test.ts).
| Dialect | Base (driver) | Key differences |
|---------|---------------|-----------------|
| TiDB | MySQL (mysql2) | AUTO_RANDOM, SHARD_ROW_ID_BITS/PRE_SPLIT_REGIONS, SPLIT TABLE |
| SingleStore | MySQL (mysql2) | SHARD KEY/SORT KEY, ROWSTORE/columnstore, REFERENCE tables, FK omitted |
| Databricks | MySQL (mysql2) | USING DELTA, MERGE INTO upsert, Spark types, GENERATED ALWAYS AS IDENTITY |
| YugabyteDB | PostgreSQL (pg) | SPLIT INTO TABLETS, colocation, HASH primary keys, tablegroups |
| TimescaleDB | PostgreSQL (pg) | create_hypertable, compression/retention policies, continuous aggregates |
| Greenplum | PostgreSQL (pg) | DISTRIBUTED BY, append-optimized storage, external tables, staging-table upsert |
| Vertica | PostgreSQL (pg) | ORDER BY/SEGMENTED BY, projections, IDENTITY, LONG VARCHAR |
| Trino | PostgreSQL (pg) | catalog.schema.table, WITH (format=…), CTAS, no PK/FK/index |
| Exasol | PostgreSQL (pg) | DISTRIBUTE BY, IDENTITY, IMPORT/EXPORT, MERGE upsert |
| QuestDB | PostgreSQL (pg) | designated TIMESTAMP, PARTITION BY, SYMBOL, DEDUP |
| CrateDB | PostgreSQL (pg) | CLUSTERED/PARTITIONED, OBJECT/ARRAY types |
| Firebird | PostgreSQL (pg) | FIRST/SKIP paging, GENERATED … IDENTITY, generators |
These dialect layers are verified at the SQL-generation level (connection-free tests); end-to-end execution against a live server of each engine is not part of the automated suite. See each page's "verification status" section.
Diagrams
The src/diagrams module renders standalone SVG
diagrams from schema data — 15 generators (model card, ER, migration, UML class,
crow's-foot relational, sequence, state, dependency graph, data-dictionary,
index map, flowchart, tree, Chen-ER, package, gantt) built on a shared
DOM-backed SVG builder with light/dark themes and configurable accent colours.
import { ModelDiagram } from 'ts-prorm-orm';
new ModelDiagram({
name: 'User',
fields: { id: { type: 'INTEGER', primaryKey: true }, email: { type: 'VARCHAR(255)', unique: true } },
theme: 'dark',
color: 'emerald',
}).save('./diagrams/User.svg');See the diagram module guide for every generator.
External Fields
A model field whose contents live in an object or key-value store, while the row lives in the database. The table column holds only the object key; the ORM keeps the two in step, so the link between a row and its object isn't something you maintain by hand.
import { Prorm, DataTypes, ExternalField, Table, Column, PrimaryKey, AutoIncrement } from 'ts-prorm-orm';
import { S3Store } from 'ts-prorm-orm';
const s3 = new S3Store({ region: 'us-east-1' });
await s3.connect();
prorm.registerStore('assets', s3, { defaultBucket: 'avatars' });
@Table()
class User {
@Column(DataTypes.INTEGER())
@PrimaryKey()
@AutoIncrement()
declare id: number;
@Column(DataTypes.STRING(100))
declare name: string;
// `avatarKey` is registered for you; only the key is stored in the table
@ExternalField({ store: 'assets', contentType: 'image/png' })
declare avatar: Buffer;
}
prorm.addModel(User);
await prorm.sync();
const user = await User.create({ name: 'Ada' });
user.avatar = pngBytes;
await user.save(); // PUT to S3, then persists avatarKey
const fetched = await User.findByPk(user.id);
await fetched.loadAvatar(); // GET from S3
fetched.avatar; // Buffer
await fetched.deleteAvatar(); // removes the object and clears the key
await fetched.destroy(); // deleting the row cleans up its objectsEach external field x gets loadX(), saveX(value), deleteX() and hasX().
Any shipped store works without an adapter. S3, MinIO, R2, GCS, Azure Blob
and Redis all have different method names (putObject vs uploadObject vs
uploadBlob; deleteObject vs removeObject vs deleteBlob) — these are
normalized internally, so registerStore() takes the store directly. Key-value
stores have no bucket concept, so a configured bucket becomes a key prefix, and
binary payloads round-trip through base64.
| Option | Default | Purpose |
|--------|---------|---------|
| store | — | Name the store was registered under |
| bucket | store's defaultBucket | Bucket/container; a key prefix on key-value stores |
| keyColumn | <field>Key | Column holding the object key |
| keyPrefix | <field>/ | Prefix for generated keys |
| contentType | — | Recorded on write where the store supports it |
| encoding | buffer | buffer, utf8, or json (parsed on read, stringified on write) |
Pass your own object implementing ExternalStoreAdapter to registerStore() for
a store that isn't recognized.
NoSQL Stores
NoSQL engines don't share the SQL-shaped Dialect interface used above (no query(sql), no identifier escaping, no DDL). Instead, each is its own store class under src/nosql/<name>/, exposing the operations that engine actually supports — see each store's README for full details.
| Store | Status | Features |
|-------|--------|-----------|
| MongoDB | Stable | mongodb driver, document CRUD, filters, aggregation pipeline, indexes, multi-document transactions (requires replica set) |
| Redis | Stable | ioredis driver, string/hash/list/set/sorted-set commands, pub/sub, pipelining/MULTI, no query language |
| Amazon DynamoDB | Stable | @aws-sdk/client-dynamodb + @aws-sdk/lib-dynamodb, partition/sort-key CRUD, Query/Scan, batch and transactional writes, no arbitrary queries |
import { MongoStore, RedisStore, DynamoDbStore } from 'ts-prorm-orm';
const mongo = new MongoStore({ uri: 'mongodb://localhost:27017', database: 'app' });
await mongo.connect();
await mongo.collection('users').insertOne({ name: 'Ada' });
const redis = new RedisStore({ host: 'localhost', port: 6379 });
await redis.connect();
await redis.set('session:1', 'active', { ex: 3600 });
const dynamo = new DynamoDbStore({ region: 'us-east-1' });
await dynamo.connect();
await dynamo.putItem('Users', { id: '1', name: 'Ada' });Object storage, streaming & additional stores
Twelve more adapters cover object storage, streaming/queues, wide-column,
document, cache, and search engines. Each lazy-loads its driver (none is a
hard dependency) and accepts an injected client, so it can be used and
unit-tested without the driver installed. Full pages under
docs/stores/.
| Store | Driver | Kind |
|-------|--------|------|
| S3Store | @aws-sdk/client-s3 | Amazon S3 object storage |
| GCSStore | @google-cloud/storage | Google Cloud Storage |
| AzureBlobStore | @azure/storage-blob | Azure Blob Storage |
| KafkaStore | kafkajs | Apache Kafka streaming |
| NatsStore | nats | NATS + JetStream KV |
| RabbitMQStore | amqplib | RabbitMQ / AMQP |
| CassandraStore | cassandra-driver | Apache Cassandra (CQL) |
| CouchbaseStore | couchbase | Couchbase (N1QL) |
| MemcachedStore | memjs | Memcached cache |
| SurrealStore | surrealdb | SurrealDB multi-model |
| OpenSearchStore | @opensearch-project/opensearch | OpenSearch |
| RethinkDBStore | rethinkdb-ts | RethinkDB |
import { S3Store, KafkaStore } from 'ts-prorm-orm';
const s3 = new S3Store({ region: 'us-east-1' });
await s3.connect();
await s3.putObject('bucket', 'hello.txt', 'hi');
const kafka = new KafkaStore({ clientId: 'app', brokers: ['localhost:9092'] });
await kafka.connect();
await kafka.produce('events', [{ value: JSON.stringify({ hello: 'world' }) }]);Usage Examples by Dialect
SQLite
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'sqlite',
storage: './database.db',
});
// Define model with SQLite-specific features
const User = prorm.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING,
email: DataTypes.STRING(255),
// SQLite supports virtual columns
fullName: {
type: DataTypes.VIRTUAL,
get() {
return `${this.name}`;
}
}
});
// Full-text search (FTS5 on SQLite, GIN/to_tsvector on Postgres,
// FULLTEXT on MySQL/MariaDB - the dialect decides)
await prorm.getQueryInterface().createFullTextIndex({
name: 'users_fts',
table: 'users',
columns: ['name', 'email'],
});
// Upsert (INSERT OR REPLACE)
await User.upsert({
id: 1,
name: 'John',
email: '[email protected]'
});MySQL
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'mysql',
host: 'localhost',
port: 3306,
database: 'mydb',
username: 'root',
password: 'password',
});
const User = prorm.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING(100),
email: {
type: DataTypes.STRING(255),
unique: true,
},
// MySQL JSON column
preferences: DataTypes.JSON,
// MySQL enum
status: {
type: DataTypes.ENUM('active', 'inactive', 'pending'),
defaultValue: 'active',
}
});
// Declare a stored procedure with @Procedure, then let sync() create it
import { Procedure, ProcedureRegistry } from 'ts-prorm-orm';
class UserProcedures {
@Procedure({
name: 'get_user_by_email',
params: [{ name: 'user_email', type: 'VARCHAR(255)', mode: 'IN' }],
body: 'SELECT * FROM users WHERE email = user_email;',
})
getUserByEmail(email: string) {}
}
prorm.registerProcedures(UserProcedures);
await prorm.sync(); // issues the CREATE PROCEDURE
// Call it
const rows = await ProcedureRegistry.call(
prorm, UserProcedures, 'getUserByEmail', ['[email protected]']
);PostgreSQL
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'postgres',
host: 'localhost',
port: 5432,
database: 'mydb',
username: 'postgres',
password: 'password',
});
const User = prorm.define('User', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING(100),
email: {
type: DataTypes.STRING(255),
unique: true,
},
// PostgreSQL UUID
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
},
// PostgreSQL JSONB
metadata: DataTypes.JSONB,
// PostgreSQL array
tags: DataTypes.ARRAY(DataTypes.STRING),
// PostgreSQL hstore
properties: DataTypes.HSTORE,
});
const qi = prorm.getQueryInterface();
// Row-Level Security (RLS)
await qi.enableRowLevelSecurity('users');
await qi.createPolicy({
name: 'users_policy',
table: 'users',
using: 'user_id = current_user_id()',
});
// Full-text search
await qi.createFullTextIndex({
name: 'users_fts_idx',
table: 'users',
columns: ['name', 'email'],
language: 'english',
});
// Sequence
await qi.createSequence('user_id_seq', { start: 1000 });MariaDB
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'mariadb',
host: 'localhost',
port: 3306,
database: 'mydb',
username: 'root',
password: 'password',
});
const Product = prorm.define('Product', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING(200),
price: DataTypes.DECIMAL(10, 2),
// MariaDB virtual column
price_with_tax: {
type: DataTypes.VIRTUAL,
get() {
return parseFloat(this.price) * 1.2;
}
},
// MariaDB JSON
attributes: DataTypes.JSON,
});
// Stored procedure - declared once, created by sync()
class ProductProcedures {
@Procedure({
name: 'get_products_by_price',
params: [{ name: 'min_price', type: 'DECIMAL(10,2)', mode: 'IN' }],
body: 'SELECT * FROM products WHERE price >= min_price;',
})
getProductsByPrice(minPrice: number) {}
}
prorm.registerProcedures(ProductProcedures);
await prorm.sync();
const rows = await ProcedureRegistry.call(
prorm, ProductProcedures, 'getProductsByPrice', [10.0]
);Oracle
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'oracle',
host: 'localhost',
port: 1521,
database: 'ORCL',
username: 'system',
password: 'password',
});
const Employee = prorm.define('Employee', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: DataTypes.STRING(100),
email: DataTypes.STRING(255),
// Oracle BLOB for binary data
resume: DataTypes.BLOB,
// Oracle CLOB for large text
description: DataTypes.TEXT,
});
// Oracle sequence
await prorm.getQueryInterface().createSequence('employee_seq', {
start: 1000,
increment: 1,
});
// Stored procedure with an OUT parameter
class EmployeeProcedures {
@Procedure({
name: 'get_employee_count',
params: [{ name: 'p_count', type: 'NUMBER', mode: 'OUT' }],
body: 'SELECT COUNT(*) INTO p_count FROM employees;',
})
getEmployeeCount() {}
}
prorm.registerProcedures(EmployeeProcedures);
await prorm.sync();MSSQL
import { Prorm, DataTypes } from 'ts-prorm-orm';
const prorm = new Prorm({
dialect: 'mssql',
host: 'localhost',
port: 1433,
database: 'mydb',
username: 'sa',
password: 'password',
});
const Order = prorm.define('Order', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
customer_id: DataTypes.INTEGER,
total: DataTypes.DECIMAL(10, 2),
// MSSQL datetime2
order_date: DataTypes.DATE,
// MSSQL-specific geometry
location: DataTypes.GEOMETRY('POINT'),
// MSSQL XML
details: DataTypes.XML,
});
// MSSQL sequence
await prorm.getQueryInterface().createSequence('order_id_seq', {
start: 1000,
increment: 1,
});
// Row-Level Security. SQL Server models RLS as a security policy bound to a
// predicate function rather than as a per-table policy, and prorm has no
// builder for it yet - this is one of the few places raw SQL is still needed.
await prorm.query(`
CREATE SECURITY POLICY SalesFilter
ADD FILTER PREDICATE dbo.fn_tenantAccessPredicate(TenantId)
ON dbo.Sales
`);CLI Commands
# Generate a model
npm run model:create -- --name User --attributes name:string,email:string
# Run migrations
npm run model:create
# Generate ER diagram
npm run diagram:modelDocumentation
Full documentation is in the docs/ directory — start
there for the complete index.
Core
- Defining models · Data types · Querying · Query operators
- SQL function builders · Associations · Eager loading · Scopes · Hooks · Validation · Virtual fields
- Transactions · Bulk operations · Raw queries · Streaming · Error handling
Schema
- Indexes & constraints · Schema objects (views, triggers, procedures, sequences, RLS, partitions)
- Migrations · QueryInterface · Schema diffing · Prisma import
Connections & performance
Extending & operating
- Decorators · TypeScript types · External fields · SQL constants · Extension catalogue
- Audit logging · User management · Compliance · Foreign data wrappers · Runbooks
Databases & tooling
- Database types · SQL dialects (SQLite, PostgreSQL, MySQL, MariaDB, Oracle, MSSQL, …)
- Store adapters · Graph databases · SQLite advanced
- CLI · Diagrams · Docker & sandboxes
Architecture / Component Guides
In-depth, code-level reference docs for each major subsystem, living alongside the source under src/:
- Dialects - The
Dialectinterface and per-database (SQLite/MySQL/PostgreSQL/MariaDB/Oracle/MSSQL/CockroachDB/Redshift/Db2/Snowflake/ClickHouse/DuckDB/HANA/Spanner) implementations of connections, DDL, views, partitioning, RLS, and query building. - Models - The model layer: attribute/data types,
prorm.define(), associations, scopes, indexes/constraints, and the model registry. - Query Builders - Translates
where/order/limit/includeoptions into dialect-specific SQL strings and bound parameter values. Includes a typed SQL function-builder library (src/query-builders/functions/**- window functions, date/time, JSON paths, string/math functions, CASE expressions, cross-dialect aggregates, full-text search) usable viaimport { ... } from 'ts-prorm-orm'; seesrc/query-builders/README.mdfor the function list. - Extension Catalog - A discoverability reference (not executable code) of ~124 verified real extensions/plugins/licensed features across dialects, queryable via
findExtension()/listExtensionsForDialect()/listExtensionsByCategory()/searchExtensions(). - Query Optimizers - Opt-in performance tooling (query hints, explain plans, slow-query logging, batch optimization, prepared-statement/result caching).
- Migrations - Migration files, the
Migrator,PrormMetahistory tracking, seeders,QueryInterface, and schema diffing (src/schema/). - Compliance - GDPR/privacy/security tooling layered on the ORM core: DSAR workflows, right to erasure, consent tracking, and the composite
@Securitydecorator. - Decorators - TypeScript decorator API for defining models (
@Table,@Column, etc.) plus a larger set of feature decorators for constraints, associations, and dialect-specific column types. - Connections, Transactions & Hooks - Connection pooling, connection/replica management, transactions, and the lifecycle hooks manager.
- CLI Tooling - Reference for the multiple (non-unified) CLI entry points for model generation, migrations, seeding, and diagrams.
- Utilities - Supporting modules: error hierarchy, validators, logging, audit logging, caching, diagram generation, streams, foreign-data helpers, and user management.
Online documentation: prod-orm.io — every guide above, searchable, plus the generated API reference and the browser build.
Contributing
See CONTRIBUTING.md for the development workflow, testing, the release/publish flow, and the CI/CD + deployment runbook.
License
MIT
