npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opticore-orm-orchestrator

v1.0.0

Published

ORM Orchestrator for Prisma, TypeORM, Drizzle, MikroORM

Readme

OptiCore ORM Orchestrator

Multi-ORM CLI for TypeScript — A single interactive tool to generate models/entities for Prisma, TypeORM, Drizzle ORM, MikroORM and Sequelize — part of the OptiCoreJs Framework.

The orchestrator respects each ORM's native philosophy and generates exactly what each tool expects — no intermediate abstraction layer.


Table of Contents


Supported ORMs

| ORM | Generated file(s) | Source of truth | |---|---|---| | Prisma | prisma/schema.prisma | model {} block — no TypeScript file | | TypeORM | src/entities/*.entity.ts | Class with @Entity, @Column decorators | | Drizzle ORM | src/db/schema.ts | export const users = pgTable(...) | | MikroORM | src/entities/*.entity.ts | Class with @Entity, @Property decorators | | Sequelize | src/models/*.model.ts | Class extending Model<> with @Table, @Column |


Installation

# Local installation
npm install opticore-orm-orchestrator

# Global installation
npm install -g opticore-orm-orchestrator

Run via:

npx orm-orchestrator <command>
# or
npm exec orm-orchestrator <command>

Quick Start

# 1. Initialize the orchestrator and select your ORM
npx orm-orchestrator init

# 2. Generate a model interactively
npx orm-orchestrator make:model

# 3. List all defined models
npx orm-orchestrator list

CLI Commands

init

Initializes the ORM orchestrator in the current project directory. Creates ormOrchestrator.json.

npx orm-orchestrator init

Interactive steps:

  1. Select an ORM from the list
  2. (Prisma / Drizzle only) Select the database provider
  3. Optionally set the DATABASE_URL connection string
  4. (TypeORM / MikroORM) Set the entities directory (default: src/entities)
  5. (Drizzle) Set the schema file path (default: src/db/schema.ts)
  6. (Sequelize) Set the models directory (default: src/models)

Side effects:

  • Writes ormOrchestrator.json at the project root
  • Creates necessary directories (prisma/, src/entities/, src/models/, etc.)
  • Creates .env with a default DATABASE_URL if not present
  • Creates logs/app.log for internal CLI logging

Generated ormOrchestrator.json examples:

// Prisma
{ "orm": "prisma", "prismaProvider": "postgresql" }

// TypeORM
{ "orm": "typeorm", "entitiesDir": "src/core/models" }

// Drizzle ORM
{ "orm": "drizzle", "prismaProvider": "postgresql", "drizzleSchema": "src/core/models/schema.ts" }

// MikroORM
{ "orm": "mikroorm", "entitiesDir": "src/core/models" }

// Sequelize
{ "orm": "sequelize", "modelsDir": "src/core/models" }

make:model

Launches an interactive 5-step wizard to create a new model or entity.

npx orm-orchestrator make:model
# Aliases
npx orm-orchestrator generate
npx orm-orchestrator g

Wizard steps:

| Step | What it asks | |------------------------|---| | 1 — Model identity | Model name in PascalCase (e.g. UserProfile) | | 2 — Primary key | Int autoincrement, String cuid(), String uuid(), or none | | 3 — Custom fields | Enter a property name then its type. Press <return> with an empty name to stop | | 4 — Relations | Target model, relation type table, field name, nullable, optional inverse property | | 5 — Preview | Live code preview before writing to disk |

After confirmation, files are written and the relevant migration commands are shown.

Field type input

Types are entered as plain text. Typing ? at the type prompt prints the full type table and re-asks:

> Add another property? Enter the property name (or press <return> to stop adding fields):
  title

> Field type (enter ? to see all types) [string]:
  ?

  ────────────  ──────────────────────────────
   Type          Description
  ────────────  ──────────────────────────────
   string        text / varchar
   number        integer or decimal
   boolean       true / false
   Date          date and time
   bigint        64-bit integer
   object        JSON blob
   Buffer        binary data
  ────────────  ──────────────────────────────

> Field type (enter ? to see all types) [string]:
  string

Relation wizard

Relations are configured through a Symfony-style interactive flow:

> What class should this entity be related to?
  Category

 What type of relationship is this?
 ────────────── ──────────────────────────────────────────────────────────────
  Type           Description
 ────────────── ──────────────────────────────────────────────────────────────
  ManyToOne      Each Article relates to (has) one Category.
                 Each Category can relate to (can have) many Article objects

  OneToMany      Each Article can relate to (can have) many Category objects.
                 Each Category relates to (has) one Article

  ManyToMany     Each Article can relate to (can have) many Category objects.
                 Each Category can also relate to (can also have) many Article objects

  OneToOne       Each Article relates to (has) exactly one Category.
                 Each Category also relates to (has) exactly one Article.
 ────────────── ──────────────────────────────────────────────────────────────

> Relation type? [ManyToOne, OneToMany, ManyToMany, OneToOne]:
  ManyToOne

> Field name in Article: [category]

> Is the Article.category property allowed to be null (nullable)? (yes/no)
  yes

> Do you want to add a new property to Category so that you can access/update Article objects from it? – e.g. category.getArticles() (yes/no)
  yes

  A new property will also be added to the Category class so that you can access the related Article objects from it.

> New field name inside Category: [articles]

list

Lists all models/entities already defined in the current project.

npx orm-orchestrator list
# Alias
npx orm-orchestrator ls

Output:

  ✦ ORM Orchestrator — Defined models

  ORM: Prisma  |  Writes the model{} block directly in prisma/schema.prisma

  3 model(s):

   User                    prisma/schema.prisma
   Post                    prisma/schema.prisma
   Comment                 prisma/schema.prisma

Configuration File

ormOrchestrator.json is written by init and read by every other command.

interface OrmOrchestratorConfig {
  orm: 'prisma' | 'typeorm' | 'drizzle' | 'mikroorm' | 'sequelize';
  prismaProvider?: 'postgresql' | 'mysql' | 'sqlite' | 'sqlserver' | 'mongodb';
  databaseUrl?: string;
  entitiesDir?: string;
  modelsDir?: string;
  drizzleSchema?: string;
}

Good to know:

  Drizzle : schema file path. Default: "src/core/models/schema.ts" 
  Sequelize : models directory. Default: "src/core/models"
  TypeORM : MikroORM — entities directory. Default: "src/core/models"
  Optional : stored connection string (otherwise read from DATABASE_URL env var)
  Prisma : Drizzle — database driver
  The active ORM

Field Types

| Wizard label | TypeScript | Prisma | TypeORM | Drizzle (pg) | Sequelize | |---|---|---|---|---|---| | string | string | String | varchar | text | STRING | | number | number | Int | int | integer | INTEGER | | boolean | boolean | Boolean | boolean | boolean | BOOLEAN | | Date | Date | DateTime | timestamp | timestamp | DATE | | bigint | bigint | BigInt | bigint | bigint | BIGINT | | object | object | Json | json | jsonb | JSON | | Buffer | Buffer | Bytes | bytea | bytea | BLOB |

Type names are entered as free text. Enter ? at the type prompt to display the full table above and re-prompt.

Field options available during the wizard:

| Option | Description | |---|---| | Default value | autoincrement(), cuid(), uuid(), now(), true/false, or a literal string/number | | Unique | Adds a UNIQUE constraint | | Nullable | Makes the field optional (? in TypeScript, NULL in SQL) |


Relations

All four standard association types are supported. The wizard always asks whether to declare an inverse property on the target model (e.g. adding articles inside Category so you can navigate back from a Category to its Article objects).

OneToManycurrent model has many of target

User ─── (has many) ──► Post

| ORM | Generated output | |---|---| | Prisma | posts Post[] on User; inverse ManyToOne injected automatically into Post | | TypeORM | @OneToMany(() => Post, post => post.user) | | MikroORM | @OneToMany(() => Post, ...) with Collection<Post> | | Sequelize | @HasMany(() => Post) |


ManyToOnecurrent model belongs to target

Post ─── (belongs to) ──► User

Generates a foreign-key column (e.g. userId) alongside the relation field.

| ORM | Generated output | |---|---| | Prisma | userId Int? + @relation(fields: [userId], references: [id]) | | TypeORM | @ManyToOne + @JoinColumn({ name: 'userId' }) | | MikroORM | @ManyToOne(() => User, { nullable: true }) | | Sequelize | Explicit @ForeignKey column + @BelongsTo |


OneToOnecurrent model has exactly one of target

Generates a @unique foreign-key column on the owning side.

| ORM | Generated output | |---|---| | Prisma | @unique on the FK field | | TypeORM | @OneToOne + @JoinColumn | | MikroORM | @OneToOne(() => Target) | | Sequelize | @BelongsTo (owning side) or @HasOne (inverse) |


ManyToManyshares many of target via pivot table

| ORM | Generated output | |---|---| | Prisma | Target[] field (implicit pivot table managed by Prisma) | | TypeORM | @ManyToMany + @JoinTable({ name: '...' }) | | MikroORM | @ManyToMany with Collection<Target> | | Sequelize | @BelongsToMany + a dedicated join-table model file is generated automatically |


ORM Adapters

Prisma

Strategy: Writes model {} blocks directly into prisma/schema.prisma. No TypeScript entity file.

  • Creates prisma/schema.prisma with generator client and datasource db blocks if absent
  • Updates existing models in place using regex matching
  • Automatically injects inverse relation fields into already-defined models

TypeORM

Strategy: Generates src/entities/<name>.entity.ts — the TypeScript class is the entity.

  • Only the necessary decorators are imported (tree-shaken import list)
  • Related entity imports are added automatically
  • Supports @PrimaryGeneratedColumn(), @PrimaryGeneratedColumn('uuid'), @CreateDateColumn(), @UpdateDateColumn()

Drizzle ORM

Strategy: Generates/updates a single src/db/schema.ts — the TypeScript file is the schema.

  • Driver-aware: uses pgTable / mysqlTable / sqliteTable based on prismaProvider
  • SQL function defaults (e.g. now()) use the sql template tag from drizzle-orm
  • Relations declared with the relations() helper in the same file
  • Merges missing sql and relations imports automatically on each write

MikroORM

Strategy: Generates src/entities/<name>.entity.ts — the TypeScript class is the entity.

  • OneToMany and ManyToMany use Collection<T> initialized inline
  • Decorator options are built dynamically (only non-default options are included)

Sequelize

Strategy: Generates src/models/<name>.model.ts — the class extends Model<> from sequelize-typescript.

Extra files generated automatically:

| Situation | Extra file | |---|---| | ManyToMany relation | Dedicated join-table model (e.g. user-tag.model.ts) | | Any model | src/models/index.ts barrel is created or updated |


Generated Output Examples

Prisma

model User {
  id               Int          @id @default(autoincrement())
  createdAt        DateTime     @default(now())
  updatedAt        DateTime     @updatedAt
  email            String       @unique
  name             String?

  posts            Post[]

  @@map("users")
}

TypeORM

// src/entities/post.entity.ts
import {
  Entity, Column, PrimaryGeneratedColumn,
  CreateDateColumn, UpdateDateColumn,
  ManyToOne, JoinColumn
} from 'typeorm';
import { User } from './user.entity';

@Entity()
export class Post {

  @PrimaryGeneratedColumn()
  id!: number;

  @CreateDateColumn()
  createdAt!: Date;

  @UpdateDateColumn()
  updatedAt!: Date;

  @Column('varchar', { unique: true })
  title!: string;

  @ManyToOne(() => User, (user) => user.posts, { nullable: true })
  @JoinColumn({ name: 'userId' })
  user?: User;
}

Drizzle ORM (PostgreSQL)

// src/db/schema.ts
import { pgTable, relations } from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';

export const posts = pgTable('posts', {
  id:        integer('id').primaryKey().autoIncrement(),
  createdAt: timestamp('createdAt').default(sql`now()`).notNull(),
  updatedAt: timestamp('updatedAt').$onUpdate(() => new Date()),
  title:     text('title').notNull(),
  userId:    integer('userId'),
});

export const postsRelations = relations(posts, ({ one }) => ({
  user: one(users, { fields: [posts.userId], references: [users.id] }),
}));

MikroORM

// src/entities/comment.entity.ts
import {
  Entity, Property, PrimaryKey, ManyToOne
} from '@mikro-orm/core';
import { Post } from './post.entity';

@Entity()
export class Comment {

  @PrimaryKey()
  id!: number;

  @Property({ default: 'now()' })
  createdAt!: Date;

  @Property({ onUpdate: () => new Date() })
  updatedAt!: Date;

  @Property()
  body!: string;

  @ManyToOne(() => Post, { nullable: true })
  post?: Post;
}

Sequelize

// src/models/user.model.ts
import {
  Table, Column, Model, DataType,
  PrimaryKey, AutoIncrement,
  CreatedAt, UpdatedAt, Unique, HasMany
} from 'sequelize-typescript';
import { Post } from './post.model';

@Table({ timestamps: true, underscored: true })
export class User extends Model<User> {

  @PrimaryKey
  @AutoIncrement
  @Column(DataType.INTEGER)
  id!: number;

  @CreatedAt
  createdAt!: Date;

  @UpdatedAt
  updatedAt!: Date;

  @Unique
  @Column({ type: DataType.STRING, allowNull: false })
  email!: string;

  @HasMany(() => Post, { foreignKey: 'userId', onDelete: 'SET NULL' })
  posts?: Post[];
}
// src/models/post-tag.model.ts  ← auto-generated for ManyToMany
import { Table, Column, Model, ForeignKey } from 'sequelize-typescript';
import { Post } from './post.model';
import { Tag } from './tag.model';

@Table({ tableName: 'post_tag', timestamps: false })
export class PostTag extends Model<PostTag> {

  @ForeignKey(() => Post)
  @Column
  postId!: number;

  @ForeignKey(() => Tag)
  @Column
  tagId!: number;
}
// src/models/index.ts  ← barrel auto-maintained
export { User }    from './user.model';
export { Post }    from './post.model';
export { Tag }     from './tag.model';
export { PostTag } from './post-tag.model';

Next Steps After Generation

| ORM | Commands | |---|---| | Prisma | npx prisma migrate dev · npx prisma generate | | TypeORM | npm run migration:generate · npm run migration:run | | Drizzle ORM | npx drizzle-kit generate · npx drizzle-kit migrate | | MikroORM | npm run migration:generate · npm run migration:run | | Sequelize | npx sequelize-cli db:migrate |


Type Reference

OrmType

type OrmType = 'prisma' | 'typeorm' | 'drizzle' | 'mikroorm' | 'sequelize';

ScalarType

type ScalarType = 'string' | 'number' | 'boolean' | 'Date' | 'bigint' | 'object' | 'Buffer';

RelationType

type RelationType = 'OneToOne' | 'OneToMany' | 'ManyToOne' | 'ManyToMany';

FieldDefinition

interface FieldDefinition {
  name:        string;
  type:        ScalarType;
  default?:    string | number | boolean;
  primary?:    boolean;
  unique?:     boolean;
  nullable?:   boolean;
  onUpdate?:   boolean; 
  columnName?: string;
  length?:     number; 
}

Good to know

  default? : autoincrement()', 'now()', 'cuid()', true, 0, …
  onUpdate? :  @updatedAt / @UpdateDateColumn / $onUpdate hook
  columnName?: Custom SQL column name (overrides field name)
  length?: Column length — used by VARCHAR / STRING

RelationDefinition

interface RelationDefinition {
  type:          RelationType;
  target:        string;
  field:         string;
  foreignKey?:   string;
  references?:   string;
  nullable?:     boolean;
  joinTable?:    string;
  inverseField?: string;
}

Good to know

  target:        Target model name (PascalCase)
  field:         Property name on the owning model
  foreignKey?:   FK column name — default: `${field}Id`
  references?:   Referenced column — default: 'id'
  nullable?:     Whether the relation field is nullable
  joinTable?:    Explicit pivot table name (ManyToMany)
  inverseField?: Property name added to the target model for the inverse side
                 (e.g. "articles" inside Category pointing back to Article)

ModelDefinition

interface ModelDefinition {
  name:       string;
  fields:     FieldDefinition[];
  relations?: RelationDefinition[];
  tableName?: string;
}

Good to know

   tableName?: Custom SQL table name (@@map / tableName option)
   installed: Packages already in node_modules
   missing:   Production packages to install
   missingDev: Dev packages to install

OrmOrchestratorConfig

interface OrmOrchestratorConfig {
  orm:             OrmType;
  prismaProvider?: 'postgresql' | 'mysql' | 'sqlite' | 'sqlserver' | 'mongodb';
  databaseUrl?:    string;
  entitiesDir?:    string;
  modelsDir?:      string;
  drizzleSchema?:  string;
}

CheckResult

interface CheckResult {
  installed:   string[];
  missing:     string[];
  missingDev:  string[];
}

Good to know

   installed: Packages already in node_modules
   missing: Production packages to install
   missingDev: Dev packages to install

Contributors

This package is led by Guy-serge Kouacou.

Contributing

This project welcomes contributions from the community. Contributions are accepted using GitHub pull requests. If you're not familiar with making GitHub pull requests, please refer to the GitHub documentation "Creating a pull request."

License

MIT — part of the OptiCoreJs Framework.