Skip to content

Installation

Chapter 4: TypeORM Installation & Configuration

Section titled “Chapter 4: TypeORM Installation & Configuration”

TypeORM Installation Flow
================================================================================
Step 1: Install Dependencies
+-------------------+
| npm install |
| typeorm |
| reflect-metadata |
| database-driver |
+-------------------+
|
v
Step 2: Configure TypeScript
+-------------------+
| tsconfig.json |
| - decorators |
| - emit metadata |
+-------------------+
|
v
Step 3: Create DataSource
+-------------------+
| data-source.ts |
| - connection |
| - entities |
| - migrations |
+-------------------+
|
v
Step 4: Initialize in App
+-------------------+
| app.module.ts |
| or index.ts |
+-------------------+
================================================================================

Terminal window
# Install TypeORM core
npm install typeorm reflect-metadata
# Install database driver (choose one)
npm install pg # PostgreSQL (recommended)
npm install mysql2 # MySQL
npm install sqlite3 # SQLite
npm install better-sqlite3 # SQLite (better performance)
npm install mongodb # MongoDB
npm install oracledb # Oracle
npm install mssql # Microsoft SQL Server
Terminal window
# Create new NestJS project
npm i -g @nestjs/cli
nest new my-project
cd my-project
# Install TypeORM for NestJS
npm install typeorm @nestjs/typeorm @nestjs/config
# Install database driver
npm install pg
# Install validation (recommended)
npm install class-validator class-transformer

TypeORM requires specific TypeScript compiler options.

tsconfig.json
{
"compilerOptions": {
// Required for TypeORM decorators
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
// Required for proper type reflection
"strictPropertyInitialization": false,
// Recommended settings
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
// Output configuration
"outDir": "./dist",
"rootDir": "./src",
// Module resolution
"moduleResolution": "node",
"module": "commonjs",
"target": "ES2021",
// Source maps for debugging
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
TypeScript Configuration Explained
+------------------------------------------------------------------+
| |
| experimentalDecorators: true |
| +----------------------------------------------------------+ |
| | Enables @Entity(), @Column() and other decorators | |
| | Without this, decorators will cause compile errors | |
| +----------------------------------------------------------+ |
| |
| emitDecoratorMetadata: true |
| +----------------------------------------------------------+ |
| | Allows TypeORM to infer column types from TypeScript | |
| | @Column() name: string; --> TypeORM knows it's VARCHAR | |
| +----------------------------------------------------------+ |
| |
| strictPropertyInitialization: false |
| +----------------------------------------------------------+ |
| | Allows class properties without initial values | |
| | class User { name: string; } // OK without = '' | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

src/data-source.ts
import { DataSource } from 'typeorm';
import { User } from './entities/user.entity';
import { Post } from './entities/post.entity';
export const AppDataSource = new DataSource({
type: 'postgres', // Database type
host: 'localhost', // Database host
port: 5432, // Database port
username: 'postgres', // Database username
password: 'password', // Database password
database: 'my_app', // Database name
// Entities
entities: [User, Post], // Or use: ['src/entities/**/*.ts']
// Migrations
migrations: ['src/migrations/**/*.ts'],
migrationsRun: false, // Auto-run migrations on startup
// Synchronization (development only!)
synchronize: false, // NEVER use true in production!
// Logging
logging: true, // Log SQL queries
// Connection pool
poolSize: 10, // Number of connections in pool
});
src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
export const getDatabaseConfig = (
configService: ConfigService
): TypeOrmModuleOptions => ({
type: 'postgres',
host: configService.get('DB_HOST', 'localhost'),
port: configService.get('DB_PORT', 5432),
username: configService.get('DB_USERNAME', 'postgres'),
password: configService.get('DB_PASSWORD', 'password'),
database: configService.get('DB_NAME', 'my_app'),
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
synchronize: configService.get('NODE_ENV') === 'development',
logging: configService.get('NODE_ENV') === 'development',
// Connection pool settings
extra: {
max: 20, // Maximum connections
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000, // Connection timeout
},
});
src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { getDatabaseConfig } from './config/database.config';
import { UsersModule } from './users/users.module';
@Module({
imports: [
// Load environment variables
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
}),
// Configure TypeORM
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: getDatabaseConfig,
}),
// Feature modules
UsersModule,
],
})
export class AppModule {}

Terminal window
# .env (never commit this file!)
DB_TYPE=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password
DB_NAME=my_app
# Environment
NODE_ENV=development
# Additional settings
DB_SYNCHRONIZE=false
DB_LOGGING=true
DB_POOL_SIZE=10
Terminal window
# .env.example (commit this file)
DB_TYPE=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=
DB_NAME=my_app
NODE_ENV=development
DB_SYNCHRONIZE=false
DB_LOGGING=true
DB_POOL_SIZE=10
src/config/database.config.ts
import { DataSourceOptions } from 'typeorm';
export const databaseConfig: DataSourceOptions = {
type: (process.env.DB_TYPE as 'postgres') || 'postgres',
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432', 10),
username: process.env.DB_USERNAME || 'postgres',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_NAME || 'my_app',
entities: ['dist/entities/**/*.js'],
migrations: ['dist/migrations/**/*.js'],
synchronize: process.env.DB_SYNCHRONIZE === 'true',
logging: process.env.DB_LOGGING === 'true',
};

import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'my_app',
// PostgreSQL-specific options
schema: 'public', // Default schema
ssl: false, // SSL connection
uuidExtension: 'uuid-ossp', // UUID extension
entities: ['src/entities/**/*.ts'],
migrations: ['src/migrations/**/*.ts'],
});
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'my_app',
// MySQL-specific options
charset: 'utf8mb4', // Character set
timezone: '+00:00', // Server timezone
entities: ['src/entities/**/*.ts'],
migrations: ['src/migrations/**/*.ts'],
});
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'better-sqlite3', // or 'sqlite'
database: 'my_app.db', // File path or ':memory:'
entities: ['src/entities/**/*.ts'],
migrations: ['src/migrations/**/*.ts'],
});

src/index.ts
import 'reflect-metadata';
import { AppDataSource } from './data-source';
async function bootstrap() {
try {
// Initialize connection
await AppDataSource.initialize();
console.log('Database connection established');
// Your application logic here
// ...
} catch (error) {
console.error('Database connection failed:', error);
process.exit(1);
}
}
bootstrap();
src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable validation globally
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
await app.listen(3000);
console.log('Application running on port 3000');
}
bootstrap();

Connection Pool Explained
+------------------------------------------------------------------+
| |
| Application |
| +------------------------+ |
| | Request 1 | |
| | Request 2 | |
| | Request 3 | |
| | ... | |
| +------------------------+ |
| | |
| v |
| +------------------------+ |
| | Connection Pool | |
| | (10 connections) | |
| | | |
| | [C1] [C2] [C3] ... [C10] |
| | | | | | |
| +---|----|----|---------|------------------------------------+ |
| | | | | |
| v v v v |
| +-----------------------------------+ |
| | Database | |
| +-----------------------------------+ |
| |
| Benefits: |
| - Reuse connections (no reconnect overhead) |
| - Limit concurrent connections |
| - Better performance under load |
| |
+------------------------------------------------------------------+
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
// ... other options
// Connection pool settings
poolSize: 10, // Number of connections
// Advanced pool settings (via extra)
extra: {
max: 20, // Maximum connections in pool
min: 5, // Minimum connections in pool
idleTimeoutMillis: 30000, // Close idle connections after 30s
connectionTimeoutMillis: 2000, // Error if can't connect in 2s
},
});

src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
// Primary database
TypeOrmModule.forRoot({
name: 'primary',
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'primary_db',
entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],
}),
// Secondary database
TypeOrmModule.forRoot({
name: 'secondary',
type: 'postgres',
host: 'localhost',
port: 5433,
username: 'postgres',
password: 'password',
database: 'secondary_db',
entities: [__dirname + '/entities/**/*.entity{.ts,.js}'],
}),
],
})
export class AppModule {}
src/users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
@Module({
imports: [
// Specify which connection to use
TypeOrmModule.forFeature([User], 'primary'),
],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}

import { DataSource, Logger } from 'typeorm';
// Custom logger
class CustomLogger implements Logger {
logQuery(query: string, parameters?: any[]) {
console.log(`[QUERY] ${query}`);
if (parameters) {
console.log(`[PARAMS] ${JSON.stringify(parameters)}`);
}
}
logMigration(message: string) {
console.log(`[MIGRATION] ${message}`);
}
logSchemaBuild(message: string) {
console.log(`[SCHEMA] ${message}`);
}
log(level: 'log' | 'info' | 'warn', message: any) {
console.log(`[${level.toUpperCase()}] ${message}`);
}
}
export const AppDataSource = new DataSource({
type: 'postgres',
// ... other options
// Logging options
logging: true, // Enable all logging
// OR
logging: ['query', 'error', 'migration'], // Selective logging
// Custom logger
logger: new CustomLogger(),
});

// ormconfig.json (alternative to programmatic config)
{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "password",
"database": "my_app",
"entities": ["src/entities/**/*.ts"],
"migrations": ["src/migrations/**/*.ts"],
"cli": {
"entitiesDir": "src/entities",
"migrationsDir": "src/migrations",
"subscribersDir": "src/subscribers"
}
}
Terminal window
# Initialize new project
typeorm init --name my-project --database postgres
# Create entity
typeorm entity:create -n User
# Create migration
typeorm migration:create -n CreateUserTable
# Create subscriber
typeorm subscriber:create -n UserSubscriber
# Run migrations
typeorm migration:run
# Revert migration
typeorm migration:revert
# Sync schema (development only!)
typeorm schema:sync
# Drop schema
typeorm schema:drop
# Generate migration from entity changes
typeorm migration:generate -n AddUserEmail

Recommended Project Structure
+------------------------------------------------------------------+
| |
| my-project/ |
| +----------------------------------------------------------+ |
| | | |
| | src/ | |
| | +----------------------------------------------------+ | |
| | | | | |
| | | config/ | | |
| | | +----------------------------------------------+ | | |
| | | | database.config.ts | | | |
| | | +----------------------------------------------+ | | |
| | | | | |
| | | entities/ | | |
| | | +----------------------------------------------+ | | |
| | | | user.entity.ts | | | |
| | | | post.entity.ts | | | |
| | | +----------------------------------------------+ | | |
| | | | | |
| | | migrations/ | | |
| | | +----------------------------------------------+ | | |
| | | | 1234567890-CreateUser.ts | | | |
| | | +----------------------------------------------+ | | |
| | | | | |
| | | modules/ | | |
| | | +----------------------------------------------+ | | |
| | | | users/ | | | |
| | | | +------------------------------------------+ | | | |
| | | | | users.module.ts | | | | |
| | | | | users.controller.ts | | | | |
| | | | | users.service.ts | | | | |
| | | | | dto/ | | | | |
| | | | | +--------------------------------------+ | | | | |
| | | | | | create-user.dto.ts | | | | | |
| | | | | | update-user.dto.ts | | | | | |
| | | | | +--------------------------------------+ | | | | |
| | | | +------------------------------------------+ | | | |
| | | +----------------------------------------------+ | | |
| | | | | |
| | | data-source.ts | | |
| | | app.module.ts | | |
| | | main.ts | | |
| | +----------------------------------------------------+ | |
| | | |
| | .env | |
| | .env.example | |
| | tsconfig.json | |
| | package.json | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Error: Unable to resolve signature of class decorator

Solution: Ensure experimentalDecorators and emitDecoratorMetadata are enabled in tsconfig.json.

Error: connect ECONNREFUSED 127.0.0.1:5432

Solution:

  1. Verify database is running
  2. Check host and port in configuration
  3. Verify firewall settings
Error: password authentication failed for user "postgres"

Solution:

  1. Verify username and password
  2. Check database user permissions
  3. Check pg_hba.conf for PostgreSQL
Error: No metadata for "User" was found

Solution:

  1. Ensure entity is registered in DataSource
  2. Check entity path pattern
  3. Verify @Entity() decorator is present

Installation Checklist
+------------------------------------------------------------------+
| |
| [ ] Install typeorm and reflect-metadata |
| [ ] Install database driver (pg, mysql2, etc.) |
| [ ] Configure tsconfig.json (decorators enabled) |
| [ ] Create data-source.ts or database.config.ts |
| [ ] Set up .env file with database credentials |
| [ ] Configure connection pool settings |
| [ ] Initialize connection in app.module.ts or index.ts |
| [ ] Test connection with simple query |
| |
+------------------------------------------------------------------+

Chapter 5: Connection & DataSource Setup


Last Updated: February 2026