typeorm/typeorm

TypeScript & JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.

36,446 stars TypeScript 10 components

12 hidden assumptions · 6-stage pipeline · 10 components

Like any codebase, this library makes assumptions it never checks — most are routine. The ones worth your attention are below.

Maps TypeScript objects to database tables with type-safe queries across 8 database types

Data enters through entity decorators that get collected into MetadataArgsStorage during class definition. When DataSource initializes, ConnectionMetadataBuilder processes these into EntityMetadata objects. User queries flow through Repository or EntityManager APIs, get transformed into QueryBuilder instances, then compiled by database-specific drivers into native SQL/NoSQL. Results return through QueryRunner back to EntityManager, which maps raw data into typed entity instances using the metadata.

Under the hood, the system uses 4 feedback loops, 5 data pools, 5 control points to manage its runtime behavior.

A 10-component library. 3507 files analyzed. Data flows through 6 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If decorators execute on other classes while ConnectionMetadataBuilder is processing MetadataArgsStorage, the builder might miss new entities or process incomplete metadata, leading to 'Entity metadata not found' errors at runtime

Worth your attention first

If transforms run out of order, later transforms will fail to find renamed identifiers, causing incomplete code migration where some Connection references remain unconverted

Worth your attention first

If user calls getRepository() with an entity class that wasn't included in DataSourceOptions.entities or failed metadata validation, throws EntityMetadataNotFoundError at runtime instead of initialization

Show everything (9 more)
Environment

Database connection parameters in DataSourceOptions remain valid throughout application lifecycle - host, port, credentials don't change

If this fails: If database connection details change after DataSource initialization (like in containerized environments), existing connections silently fail with cryptic network errors instead of attempting reconnection

src/data-source/DataSource.ts:initialize
Scale

Worker count in codemod transform execution is bounded by available CPU cores and memory can handle processing all target files simultaneously

If this fails: In large codebases with thousands of files, excessive worker spawning can exhaust memory or file descriptors, causing transform process to crash mid-migration with partial file changes

packages/codemod/src/cli/run.ts:workers
Resource

entityMetadatas Map can hold metadata for all registered entities in memory without memory pressure, regardless of application size

If this fails: In applications with hundreds of entities, the metadata cache grows unbounded and never releases memory, eventually causing OOM in long-running processes

src/data-source/DataSource.ts:EntityMetadata
Domain

Version strings in dependency configs exactly match user-provided version parameter with no normalization or fuzzy matching

If this fails: If user specifies 'v1.0' instead of 'v1' or includes patch versions like 'v1.2.3', getConfig returns undefined and codemod fails with 'unknown version' error

packages/codemod/src/dependencies/index.ts:getConfig
Contract

Isolation level parameter passed to transaction() is one of the driver-supported values, with no cross-database validation

If this fails: If code passes PostgreSQL-specific isolation level to MySQL driver, or vice versa, transaction starts with default isolation instead of failing fast, causing subtle concurrency bugs

src/data-source/DataSource.ts:transaction
Temporal

All active QueryRunners and EntityManagers are released before DataSource.destroy() is called, with no pending transactions

If this fails: If destroy() is called while queries are in flight, connection pool closes abruptly causing active queries to fail with connection errors instead of graceful completion

src/data-source/DataSource.ts:destroy
Ordering

Transform resolution happens before any file processing begins, with transform dependencies fully resolved at start

If this fails: If transforms have circular dependencies or missing dependencies, resolution may succeed but execution fails partway through processing, leaving codebase in inconsistent state

packages/codemod/src/transforms/resolve.ts:resolveTransforms
Environment

Process exit with code 1 on error is appropriate for all environments - CI systems, IDEs, shell scripts expect this convention

If this fails: In environments expecting different exit codes for different error types, blanket process.exit(1) makes error diagnosis harder and may break automated tooling

packages/codemod/src/index.ts:main
Shape

Command line arguments follow expected format with proper flag parsing, no validation of argument combinations or required dependencies

If this fails: If user passes conflicting flags like '--dry --workers 0' or malformed paths, parseArgs succeeds but later processing fails with confusing errors instead of helpful usage message

packages/codemod/src/cli/parse-args.ts:parseArgs

Open the standalone hidden-assumptions report for typeorm →

How Data Flows Through the System

Data enters through entity decorators that get collected into MetadataArgsStorage during class definition. When DataSource initializes, ConnectionMetadataBuilder processes these into EntityMetadata objects. User queries flow through Repository or EntityManager APIs, get transformed into QueryBuilder instances, then compiled by database-specific drivers into native SQL/NoSQL. Results return through QueryRunner back to EntityManager, which maps raw data into typed entity instances using the metadata.

  1. Entity Definition Processing — Decorators like @Entity, @Column, @ManyToOne execute during class definition, calling getMetadataArgsStorage() to register EntityMetadataArgs, ColumnMetadataArgs, and RelationMetadataArgs in global storage [TypeScript classes with decorators → MetadataArgsStorage collections]
  2. Metadata Compilation — DataSource.initialize() creates ConnectionMetadataBuilder which processes MetadataArgsStorage contents, validates relationships, and builds complete EntityMetadata objects with table names, column mappings, and relation definitions [MetadataArgsStorage collections → EntityMetadata]
  3. Query Construction — Repository methods like find() or EntityManager operations convert FindOptions into SelectQueryBuilder instances, applying joins, conditions, ordering using EntityMetadata to ensure type safety [FindOptions → QueryBuilder Result]
  4. Query Translation — Database-specific drivers (PostgresDriver, MysqlDriver, etc.) compile QueryBuilder instances into native SQL using their buildSelectSql() methods, handling dialect differences and parameter binding [QueryBuilder Result → Native SQL queries]
  5. Query Execution — QueryRunner executes SQL against database connection pools, handling transactions, connection management, and returning raw database results with affected row counts and generated IDs [Native SQL queries → QueryRunnerResult]
  6. Result Mapping — EntityManager transforms raw QueryRunnerResult data back into typed entity instances using EntityMetadata column mappings, handling nested relations and lazy loading proxies [QueryRunnerResult → Entity instances]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

EntityMetadata src/metadata/EntityMetadata.ts
Complex object with target: Function (entity class), tableName: string, columns: ColumnMetadata[], relations: RelationMetadata[], indices: IndexMetadata[], checks: CheckMetadata[], primaryColumns: ColumnMetadata[], generatedColumns: ColumnMetadata[]
Created during DataSource initialization by scanning entity decorators, stored in MetadataArgsStorage, then used throughout the application lifecycle for all database operations
QueryBuilder Result src/query-builder/QueryBuilder.ts
Generic type T where T extends ObjectLiteral - the entity type being queried, with additional metadata like alias tables and parameter bindings
Built incrementally through method chaining (.select(), .where(), .join()), compiled to SQL by driver, executed against database, then mapped back to entity instances
FindOptions src/find-options/FindManyOptions.ts
Interface with select?: FindOptionsSelect<Entity>, relations?: FindOptionsRelations<Entity>, where?: FindOptionsWhere<Entity>, order?: FindOptionsOrder<Entity>, skip?: number, take?: number, cache?: boolean | number | FindOptionsCache
Created by user API calls to repository.find(), transformed into QueryBuilder operations, then executed as SQL queries
DataSourceOptions src/data-source/DataSourceOptions.ts
Union type of database-specific options extending BaseDataSourceOptions with type: DatabaseType, host?: string, port?: number, database?: string, entities: MixedList<Function | string | EntitySchema>, migrations?: MixedList<Function | string>
Provided by user during DataSource construction, validated and used to configure database drivers and establish connections
Migration src/migration/Migration.ts
Interface with id?: number, timestamp: number, name: string, instance?: MigrationInterface
Discovered from migration files or classes, executed in timestamp order via MigrationExecutor, with results tracked in migrations table
QueryRunnerResult src/query-runner/QueryRunner.ts
Database-specific result object containing records: any[], affected?: number, insertId?: any, raw?: any - varies by database type
Returned by database drivers after query execution, transformed by EntityManager into entity instances or raw results

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

MetadataArgsStorage (registry)
Global singleton that accumulates decorator metadata during TypeScript class definition - stores arrays of entity, column, relation, and index arguments before processing
EntityMetadata Cache (in-memory)
DataSource maintains entityMetadatas Map keyed by entity target classes, providing fast lookup of table schemas, column mappings, and relationship definitions
Connection Pool (buffer)
Each database driver maintains a pool of active connections that are reused across queries to avoid connection setup overhead
Query Result Cache (cache)
Optional caching layer that stores query results keyed by SQL string and parameters, reducing database round trips for repeated queries
Migration History Table (database)
Database table that tracks executed migrations by timestamp and name, preventing duplicate execution and enabling rollback capabilities

Feedback Loops

Delays

Control Points

Technology Stack

reflect-metadata (library)
Enables reading TypeScript design-time type information at runtime for automatic column type inference and validation
TypeScript (runtime)
Primary language providing decorators, type safety, and design-time metadata for entity definition and query building
Database-specific drivers (database)
Native database client libraries (pg, mysql2, sqlite3, mongodb, etc.) wrapped by TypeORM driver abstractions
JSCodeshift (build)
Powers the codemod tool for automated migration between TypeORM versions via AST transformations
Mocha (testing)
Test framework for the extensive test suite covering functional behavior across all supported databases
Gulp (build)
Build system that compiles TypeScript, packages for different environments (Node.js, browser), and handles platform-specific builds

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Library Repositories

Frequently Asked Questions

What is typeorm used for?

Maps TypeScript objects to database tables with type-safe queries across 8 database types typeorm/typeorm is a 10-component library written in TypeScript. Data flows through 6 distinct pipeline stages. The codebase contains 3507 files.

How is typeorm architected?

typeorm is organized into 5 architecture layers: Entity Definition Layer, Metadata System, Query Building Layer, Driver Abstraction Layer, and 1 more. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through typeorm?

Data moves through 6 stages: Entity Definition Processing → Metadata Compilation → Query Construction → Query Translation → Query Execution → .... Data enters through entity decorators that get collected into MetadataArgsStorage during class definition. When DataSource initializes, ConnectionMetadataBuilder processes these into EntityMetadata objects. User queries flow through Repository or EntityManager APIs, get transformed into QueryBuilder instances, then compiled by database-specific drivers into native SQL/NoSQL. Results return through QueryRunner back to EntityManager, which maps raw data into typed entity instances using the metadata. This pipeline design reflects a complex multi-stage processing system.

What technologies does typeorm use?

The core stack includes reflect-metadata (Enables reading TypeScript design-time type information at runtime for automatic column type inference and validation), TypeScript (Primary language providing decorators, type safety, and design-time metadata for entity definition and query building), Database-specific drivers (Native database client libraries (pg, mysql2, sqlite3, mongodb, etc.) wrapped by TypeORM driver abstractions), JSCodeshift (Powers the codemod tool for automated migration between TypeORM versions via AST transformations), Mocha (Test framework for the extensive test suite covering functional behavior across all supported databases), Gulp (Build system that compiles TypeScript, packages for different environments (Node.js, browser), and handles platform-specific builds). A focused set of dependencies that keeps the build manageable.

What system dynamics does typeorm have?

typeorm exhibits 5 data pools (MetadataArgsStorage, EntityMetadata Cache), 4 feedback loops, 5 control points, 4 delays. The feedback loops handle cache-invalidation and auto-scale. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does typeorm use?

6 design patterns detected: Decorator Metadata Collection, Multi-Database Driver Abstraction, Fluent Query Builder, Dual Repository Pattern, Lazy Loading Proxies, and 1 more.

Analyzed on April 20, 2026 by CodeSea. Written by .