@zola_do/typeorm
v0.2.9
Published
TypeORM configuration for NestJS
Maintainers
Readme
@zola_do/typeorm
TypeORM configuration helpers and service for NestJS applications.
Overview
@zola_do/typeorm provides:
- Environment-based Configuration — Database settings from environment variables
- Auto-entity Discovery — Automatically loads entities and migrations
- DataSource Options — TypeORM 0.3+ and 1.0 compatible configuration
- Config Service — Injectable service for database access
Installation
# Install individually
npm install @zola_do/typeorm
# Or via meta package
npm install @zola_do/nestjs-sharedDependencies
npm install @nestjs/typeorm typeorm dotenvtypeorm-extension is optional (for seeding CLI). @zola_do/typeorm exports a local SeederOptions type so seed config works without importing typeorm-extension.
TypeORM 1.0: Use @nestjs/typeorm ≥ 11.0.1 and Node.js 20+. Peer range supports ^0.3.0 || ^1.0.0.
Read replicas (TypeORM replication)
@zola_do/typeorm exposes dataSourceOptions as a starting point. For read scaling, use TypeORM's replication option in the object you pass to TypeOrmModule.forRoot: supply master (writer) and slaves (readers). Environment variables are then modeled in your app (for example DATABASE_REPLICA_HOSTS parsed to an array) rather than hard-coded in the library.
Quick Start
1. Configure Environment
# .env
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp
DATABASE_USER=postgres
DATABASE_PASSWORD=secret
APP_NAME=myapp2. Register in AppModule
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { dataSourceOptions } from '@zola_do/typeorm';
@Module({
imports: [TypeOrmModule.forRoot(dataSourceOptions)],
})
export class AppModule {}3. Use Entities
import { CommonEntity } from '@zola_do/nestjs-shared';
import { Entity, Column } from 'typeorm';
@Entity('products')
export class Product extends CommonEntity {
@Column()
name: string;
@Column('decimal', { precision: 10, scale: 2 })
price: number;
}Entity Configuration
CommonEntity
All entities should extend CommonEntity for consistent audit fields:
import { CommonEntity } from '@zola_do/nestjs-shared';
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('products')
export class Product extends CommonEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
}CommonEntity Fields
| Field | Type | Description |
| ----------- | -------- | -------------------------------- |
| id | UUID | Primary key (auto-generated) |
| createdAt | Date | Auto-set on creation |
| updatedAt | Date | Auto-updated on changes |
| createdBy | string | Nullable - user who created |
| updatedBy | string | Nullable - user who last updated |
| deletedAt | Date | Nullable - soft delete timestamp |
Entity Patterns
Basic Entity
@Entity('categories')
export class Category extends CommonEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ nullable: true })
description: string;
@OneToMany(() => Product, (product) => product.category)
products: Product[];
}Entity with Relations
@Entity('orders')
export class Order extends CommonEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
customerId: string;
@Column('decimal', { precision: 10, scale: 2 })
total: number;
@Column({ default: 'pending' })
status: string;
@ManyToOne(() => Customer, (customer) => customer.orders)
@JoinColumn({ name: 'customerId' })
customer: Customer;
@OneToMany(() => OrderItem, (item) => item.order)
items: OrderItem[];
}Entity with Indexes
@Entity('products', {
indexes: [
{ name: 'idx_product_name', columns: ['name'] },
{ name: 'idx_product_status_price', columns: ['status', 'price'] },
],
})
export class Product extends CommonEntity {
@Column()
name: string;
@Column({ default: 'active' })
status: string;
@Column('decimal', { precision: 10, scale: 2 })
price: number;
}TypeOrmConfigHelper
Access individual configuration values:
import { TypeOrmConfigHelper } from '@zola_do/typeorm';
console.log(TypeOrmConfigHelper.DATABASE_HOST); // 'localhost'
console.log(TypeOrmConfigHelper.DATABASE_PORT); // 5432
console.log(TypeOrmConfigHelper.DATABASE_NAME); // 'myapp'
console.log(TypeOrmConfigHelper.DATABASE_USER); // 'postgres'
console.log(TypeOrmConfigHelper.DATABASE_PASSWORD); // 'secret'Config Keys
| Key | Type | Description |
| ------------------- | -------- | ------------------------------------- |
| DATABASE_HOST | string | Database host |
| DATABASE_PORT | number | Database port |
| DATABASE_NAME | string | Database name |
| DATABASE_USER | string | Database user |
| DATABASE_PASSWORD | string | Database password |
| APP_NAME | string | App name (fallback for DATABASE_NAME) |
TypeOrmService
Injectable service for direct database access:
import { Injectable } from '@nestjs/common';
import { TypeOrmService } from '@zola_do/typeorm';
@Injectable()
export class AnalyticsService {
constructor(private readonly typeorm: TypeOrmService) {}
async getTableStats() {
return await this.typeorm.query(`
SELECT
schemaname,
relname,
n_tup_ins as inserts,
n_tup_upd as updates,
n_tup_del as deletes
FROM pg_stat_user_tables
WHERE schemaname = 'public'
`);
}
}DataSource Options
The dataSourceOptions object provides full TypeORM configuration:
import { dataSourceOptions } from '@zola_do/typeorm';
// Full options structure
{
type: 'postgres',
host: 'localhost',
port: 5432,
database: 'myapp',
username: 'postgres',
password: 'secret',
entities: ['dist/**/*.entity.js', '**/*.entity.js'],
migrations: ['dist/**/*.migration.js', '**/*.migration.js'],
synchronize: false, // Use migrations in production
logging: process.env.NODE_ENV === 'development',
// ... more TypeORM options
}Production Configuration
// app.module.ts
import { dataSourceOptions } from '@zola_do/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
...dataSourceOptions,
synchronize: false,
migrationsRun: true,
logging: ['error', 'warn'],
}),
],
})
export class AppModule {}Environment Variables
| Variable | Description | Default |
| ------------------- | ---------------------------- | ------------------------ |
| DATABASE_HOST | Database host | localhost |
| DATABASE_PORT | Database port | 5432 |
| DATABASE_NAME | Database name | Falls back to APP_NAME |
| DATABASE_USER | Database user | postgres |
| DATABASE_PASSWORD | Database password | Required in production |
| APP_NAME | Fallback for DATABASE_NAME | — |
Validation Rules
- In production (
NODE_ENV === 'production'),DATABASE_PASSWORDis required - Either
DATABASE_NAMEorAPP_NAMEmust be set
Auto-Discovery
Entities and migrations are auto-discovered:
// dataSourceOptions.entities supports glob patterns
entities: [
__dirname + '/../../**/*.entity.js', // Compiled output
'**/*.entity.js', // Source files
];
// dataSourceOptions.migrations supports glob patterns
migrations: [__dirname + '/../../**/*.migration.js'];Entity File Location
src/
├── entities/
│ ├── base.entity.ts
│ ├── product.entity.ts
│ └── category.entity.ts
└── app.module.tsMigrations
Generate Migration
npx typeorm migration:generate -d dist/typeorm/data-source.js src/migrations/ProductColumnsRun Migrations
npx typeorm migration:run -d dist/typeorm/data-source.jsCreate Migration Manually
import { MigrationInterface, QueryRunner, Table } from 'typeorm';
export class CreateProducts1704064000000 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'products',
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
generationStrategy: 'uuid',
},
{ name: 'name', type: 'varchar' },
{ name: 'price', type: 'decimal', precision: 10, scale: 2 },
{ name: 'created_at', type: 'timestamp', default: 'now()' },
{ name: 'updated_at', type: 'timestamp', default: 'now()' },
],
}),
true,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('products');
}
}API Reference
Constants
TypeOrmConfigHelper.DATABASE_HOST;
TypeOrmConfigHelper.DATABASE_PORT;
TypeOrmConfigHelper.DATABASE_NAME;
TypeOrmConfigHelper.DATABASE_USER;
TypeOrmConfigHelper.DATABASE_PASSWORD;DataSource
import { dataSourceOptions } from '@zola_do/typeorm';
// Type: DataSourceOptionsService
import { TypeOrmService } from '@zola_do/typeorm';
@Injectable()
class MyService {
constructor(private readonly typeorm: TypeOrmService) {}
async query(sql: string, parameters?: any[]) {
return this.typeorm.query(sql, parameters);
}
}Troubleshooting
Q: Entities not being loaded?
Check glob pattern in dataSourceOptions.entities. The pattern should match your compiled .js files:
entities: [__dirname + '/../../**/*.entity.js'];Q: Migrations not running?
Ensure migrationsRun: true in production or run manually:
npm run migration:runQ: Connection refused?
Verify DATABASE_HOST and DATABASE_PORT are correct and the database is accessible.
Related Packages
- @zola_do/crud — Uses TypeORM entities
- @zola_do/collection-query — Query builder for TypeORM
License
ISC
