Skip to content

Connection_setup


In TypeORM, DataSource is the modern way to manage database connections (replacing the deprecated Connection API).

DataSource Architecture
================================================================================
DataSource
|
+-------------------+-------------------+
| | | |
v v v v
+-------+ +----------+ +--------+ +-----------+
| Entity| |Repository| | Query | |Migration |
|Manager| | Access | |Builder | | Runner |
+-------+ +----------+ +--------+ +-----------+
| | | |
+-----------+------------+--------------+
|
v
+-----------+
| Database |
+-----------+
================================================================================

import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
// ==========================================
// BASIC CONNECTION OPTIONS
// ==========================================
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
// ==========================================
// ENTITY CONFIGURATION
// ==========================================
// Option 1: Direct entity classes
entities: [User, Post, Comment],
// Option 2: Glob patterns (for compiled JS)
entities: ['dist/entities/**/*.js'],
// Option 3: Glob patterns (for TypeScript)
entities: ['src/entities/**/*.ts'],
// Option 4: Mixed
entities: [User, 'dist/entities/**/*.js'],
// ==========================================
// MIGRATION CONFIGURATION
// ==========================================
migrations: ['dist/migrations/**/*.js'],
migrationsTableName: 'migrations', // Table name for migrations
migrationsRun: false, // Auto-run on startup
// ==========================================
// SUBSCRIBER CONFIGURATION
// ==========================================
subscribers: ['dist/subscribers/**/*.js'],
// ==========================================
// SCHEMA SYNCHRONIZATION
// ==========================================
synchronize: false, // NEVER true in production!
dropSchema: false, // Drop schema on close (dev only)
// ==========================================
// LOGGING
// ==========================================
logging: true, // Enable all logging
// OR selective:
logging: ['query', 'error', 'migration', 'schema'],
// ==========================================
// CONNECTION POOL
// ==========================================
poolSize: 10, // Number of connections
// ==========================================
// NAMING STRATEGY
// ==========================================
namingStrategy: new SnakeNamingStrategy(),
// ==========================================
// CACHE
// ==========================================
cache: true, // Enable query result caching
// OR advanced:
cache: {
type: 'redis',
options: {
host: 'localhost',
port: 6379,
},
duration: 30000, // Cache duration in ms
},
});

DataSource Lifecycle
+------------------------------------------------------------------+
| |
| 1. CREATE |
| const dataSource = new DataSource({...}); |
| |
| +-------------------+ |
| | DataSource Created| |
| | (Not connected) | |
| +-------------------+ |
| | |
| v |
| 2. INITIALIZE |
| await dataSource.initialize(); |
| |
| +-------------------+ |
| | DataSource Ready | |
| | (Connected to DB) | |
| +-------------------+ |
| | |
| v |
| 3. USE |
| const users = await dataSource.getRepository(User).find(); |
| |
| +-------------------+ |
| | Execute Queries | |
| | Run Migrations | |
| +-------------------+ |
| | |
| v |
| 4. DESTROY |
| await dataSource.destroy(); |
| |
| +-------------------+ |
| | Connection Closed | |
| | Resources Freed | |
| +-------------------+ |
| |
+------------------------------------------------------------------+
src/data-source.ts
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'password',
database: 'my_app',
entities: ['dist/entities/**/*.js'],
migrations: ['dist/migrations/**/*.js'],
synchronize: false,
});
// src/index.ts
import 'reflect-metadata';
import { AppDataSource } from './data-source';
async function bootstrap() {
try {
// Initialize the connection
await AppDataSource.initialize();
console.log('DataSource initialized successfully');
// Application logic here...
} catch (error) {
console.error('Error during DataSource initialization:', error);
process.exit(1);
}
}
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('Closing application...');
if (AppDataSource.isInitialized) {
await AppDataSource.destroy();
console.log('DataSource destroyed');
}
process.exit(0);
});
bootstrap();

The EntityManager is a central service for working with entities.

Entity Manager Responsibilities
+------------------------------------------------------------------+
| |
| +----------------------------------------------------------+ |
| | EntityManager | |
| | | |
| | +----------------------------------------------------+ | |
| | | Repository Access | | |
| | | getRepository(User) | | |
| | | getCustomRepository(UserRepository) | | |
| | +----------------------------------------------------+ | |
| | | |
| | +----------------------------------------------------+ | |
| | | CRUD Operations | | |
| | | find(), findOne(), save(), remove() | | |
| | +----------------------------------------------------+ | |
| | | |
| | +----------------------------------------------------+ | |
| | | Query Builder | | |
| | | createQueryBuilder() | | |
| | +----------------------------------------------------+ | |
| | | |
| | +----------------------------------------------------+ | |
| | | Transactions | | |
| | | transaction(callback) | | |
| | +----------------------------------------------------+ | |
| | | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
import { AppDataSource } from './data-source';
import { User } from './entities/user.entity';
async function exampleUsage() {
const entityManager = AppDataSource.manager;
// Find all users
const users = await entityManager.find(User);
// Find with conditions
const activeUsers = await entityManager.find(User, {
where: { isActive: true },
order: { createdAt: 'DESC' },
take: 10,
});
// Find one
const user = await entityManager.findOne(User, {
where: { id: 1 },
relations: ['posts'],
});
// Save entity
const newUser = await entityManager.save(User, {
name: 'John Doe',
email: 'john@example.com',
});
// Remove entity
await entityManager.remove(User, { id: 1 });
// Raw query
const result = await entityManager.query('SELECT * FROM users WHERE id = $1', [1]);
// Query builder
const qb = entityManager.createQueryBuilder(User, 'user');
const usersWithPosts = await qb
.leftJoinAndSelect('user.posts', 'post')
.where('user.isActive = :active', { active: true })
.getMany();
}

Repository Access Methods
+------------------------------------------------------------------+
| |
| Method 1: From DataSource |
| +----------------------------------------------------------+ |
| | const userRepo = AppDataSource.getRepository(User); | |
| +----------------------------------------------------------+ |
| |
| Method 2: From Entity Manager |
| +----------------------------------------------------------+ |
| | const userRepo = entityManager.getRepository(User); | |
| +----------------------------------------------------------+ |
| |
| Method 3: Custom Repository |
| +----------------------------------------------------------+ |
| | const userRepo = AppDataSource | |
| | .getCustomRepository(UserRepository); | |
| +----------------------------------------------------------+ |
| |
| Method 4: Injected in NestJS |
| +----------------------------------------------------------+ |
| | constructor( | |
| | @InjectRepository(User) | |
| | private userRepo: Repository<User> | |
| | ) {} | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

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: { // SSL configuration
rejectUnauthorized: false,
},
uuidExtension: 'uuid-ossp', // UUID generation extension
// Native driver options
extra: {
ssl: true,
application_name: 'my_app',
statement_timeout: 30000, // 30 second timeout
},
});
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
connectTimeout: 10000, // Connection timeout (ms)
acquireTimeout: 10000, // Acquire timeout (ms)
insecureAuth: false, // Allow old auth
// Connection pool
extra: {
connectionLimit: 10,
waitForConnections: true,
queueLimit: 0,
},
});
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'better-sqlite3', // or 'sqlite'
database: 'my_app.db', // File path
// database: ':memory:', // In-memory database
// SQLite-specific options
prepareDatabase: (db: any) => {
db.pragma('journal_mode = WAL'); // Enable WAL mode
db.pragma('synchronous = NORMAL');
},
});
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'mongodb',
url: 'mongodb://localhost:27017', // Connection URL
database: 'my_app',
// MongoDB-specific options
authSource: 'admin',
auth: {
username: 'admin',
password: 'password',
},
useNewUrlParser: true,
useUnifiedTopology: true,
});

Connection Pool States
+------------------------------------------------------------------+
| |
| Pool Configuration |
| +----------------------------------------------------------+ |
| | | |
| | max: 20 - Maximum connections | |
| | min: 5 - Minimum idle connections | |
| | idle: 30000 - Idle timeout (ms) | |
| | acquire: 2000 - Acquire timeout (ms) | |
| | | |
| +----------------------------------------------------------+ |
| |
| Pool States |
| |
| +------------------+ |
| | Active (5) | <-- Currently executing queries |
| +------------------+ |
| | Idle (10) | <-- Available for use |
| +------------------+ |
| | Waiting (3) | <-- Requests waiting for connection |
| +------------------+ |
| |
| Request Flow: |
| |
| Request --> Get Connection --> Execute --> Release Connection |
| | | |
| v v |
| [Idle Pool] [Return to Pool] |
| |
+------------------------------------------------------------------+
import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
// ... basic options
// Pool size (TypeORM option)
poolSize: 10,
// Advanced pool options (driver-specific)
extra: {
// Maximum connections
max: 20,
// Minimum idle connections
min: 5,
// Idle timeout (ms)
idleTimeoutMillis: 30000,
// Connection timeout (ms)
connectionTimeoutMillis: 2000,
// Acquire timeout (ms)
acquireTimeoutMillis: 5000,
// Connection validation
testOnBorrow: true,
// Keep-alive
keepAlive: true,
keepAliveInitialDelay: 0,
},
});

Transaction Flow
+------------------------------------------------------------------+
| |
| Without Transaction (Dangerous!) |
| |
| Step 1: Deduct $100 from Account A |
| +-------------------+ |
| | Balance: $500->$400| |
| +-------------------+ |
| | |
| v |
| Step 2: ERROR! System crash |
| +-------------------+ |
| | Account A: $400 | <-- Lost $100! |
| | Account B: $0 | |
| +-------------------+ |
| |
+------------------------------------------------------------------+
| |
| With Transaction (Safe!) |
| |
| BEGIN TRANSACTION |
| | |
| v |
| Step 1: Deduct $100 from Account A |
| +-------------------+ |
| | Balance: $500->$400| (Not committed yet) |
| +-------------------+ |
| | |
| v |
| Step 2: ERROR! |
| +-------------------+ |
| | ROLLBACK | |
| +-------------------+ |
| | |
| v |
| Result: Account A still has $500 |
| |
+------------------------------------------------------------------+
import { AppDataSource } from './data-source';
import { User } from './entities/user.entity';
import { Account } from './entities/account.entity';
// Method 1: Using transaction callback
async function transferMoney(fromId: number, toId: number, amount: number) {
await AppDataSource.transaction(async (manager) => {
// All operations within this callback are in the same transaction
const fromAccount = await manager.findOne(Account, { where: { id: fromId } });
const toAccount = await manager.findOne(Account, { where: { id: toId } });
if (!fromAccount || !toAccount) {
throw new Error('Account not found');
}
if (fromAccount.balance < amount) {
throw new Error('Insufficient funds');
}
fromAccount.balance -= amount;
toAccount.balance += amount;
await manager.save(fromAccount);
await manager.save(toAccount);
// If any error is thrown, transaction is rolled back
// If callback completes successfully, transaction is committed
});
}
// Method 2: Manual transaction control
async function manualTransaction() {
const queryRunner = AppDataSource.createQueryRunner();
try {
// Start transaction
await queryRunner.startTransaction();
// Execute queries
const user = await queryRunner.manager.findOne(User, { where: { id: 1 } });
if (user) {
user.name = 'Updated Name';
await queryRunner.manager.save(user);
}
// Commit transaction
await queryRunner.commitTransaction();
} catch (error) {
// Rollback on error
await queryRunner.rollbackTransaction();
throw error;
} finally {
// Release query runner
await queryRunner.release();
}
}
// Method 3: Isolation levels
async function transactionWithIsolation() {
await AppDataSource.transaction(
'SERIALIZABLE', // Isolation level
async (manager) => {
// Transaction with SERIALIZABLE isolation
const users = await manager.find(User);
// ... operations
}
);
}

Multiple DataSource Architecture
+------------------------------------------------------------------+
| |
| Application |
| +----------------------------------------------------------+ |
| | | |
| | +------------------+ +------------------+ | |
| | | Primary | | Replica | | |
| | | DataSource | | DataSource | | |
| | | (Read/Write) | | (Read Only) | | |
| | +------------------+ +------------------+ | |
| | | | | |
| +---------|---------------------------|-------------------+ |
| | | |
| v v |
| +------------------+ +------------------+ |
| | Primary DB | | Replica DB | |
| | (Master) | | (Slave) | |
| +------------------+ +------------------+ |
| |
+------------------------------------------------------------------+
src/data-sources/primary.data-source.ts
import { DataSource } from 'typeorm';
export const PrimaryDataSource = new DataSource({
name: 'primary',
type: 'postgres',
host: 'primary-db.example.com',
port: 5432,
username: 'admin',
password: 'password',
database: 'my_app',
entities: ['dist/entities/**/*.js'],
migrations: ['dist/migrations/**/*.js'],
});
// src/data-sources/replica.data-source.ts
import { DataSource } from 'typeorm';
export const ReplicaDataSource = new DataSource({
name: 'replica',
type: 'postgres',
host: 'replica-db.example.com',
port: 5432,
username: 'admin',
password: 'password',
database: 'my_app',
entities: ['dist/entities/**/*.js'],
migrations: [], // No migrations on replica
});
// src/index.ts
import 'reflect-metadata';
import { PrimaryDataSource, ReplicaDataSource } from './data-sources';
async function bootstrap() {
// Initialize both connections
await Promise.all([
PrimaryDataSource.initialize(),
ReplicaDataSource.initialize(),
]);
console.log('Both DataSources initialized');
}
// Usage
async function getUser(id: number) {
// Read from replica
return ReplicaDataSource.getRepository(User).findOne({ where: { id } });
}
async function createUser(data: any) {
// Write to primary
return PrimaryDataSource.getRepository(User).save(data);
}

import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
// Write operations go to master
host: 'master-db.example.com',
port: 5432,
username: 'admin',
password: 'password',
database: 'my_app',
// Read operations go to replicas
replication: {
master: {
host: 'master-db.example.com',
port: 5432,
username: 'admin',
password: 'password',
},
slaves: [
{
host: 'replica-1.example.com',
port: 5432,
username: 'admin',
password: 'password',
},
{
host: 'replica-2.example.com',
port: 5432,
username: 'admin',
password: 'password',
},
],
},
entities: ['dist/entities/**/*.js'],
});

import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
// ... other options
});
// Listen to connection events
AppDataSource.setOptions({
// ... options
});
// After initialization
AppDataSource.initialize().then(() => {
// Connection established
console.log('Connected to database');
// Subscribe to query events
AppDataSource.queryRunner?.connection.subscribers.push({
beforeQuery: (event) => {
console.log('Before query:', event.query);
},
afterQuery: (event) => {
console.log('After query:', event.query, 'Time:', event.duration);
},
});
});

import { DataSource } from 'typeorm';
export const AppDataSource = new DataSource({
type: 'postgres',
// ... options
});
// Health check function
export async function checkDatabaseHealth(): Promise<{
status: 'healthy' | 'unhealthy';
latency?: number;
error?: string;
}> {
if (!AppDataSource.isInitialized) {
return { status: 'unhealthy', error: 'DataSource not initialized' };
}
try {
const start = Date.now();
await AppDataSource.query('SELECT 1');
const latency = Date.now() - start;
return {
status: 'healthy',
latency,
};
} catch (error) {
return {
status: 'unhealthy',
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}
// Express health endpoint
app.get('/health', async (req, res) => {
const dbHealth = await checkDatabaseHealth();
res.json({
status: dbHealth.status,
database: dbHealth,
timestamp: new Date().toISOString(),
});
});

import { DataSource, QueryFailedError } from 'typeorm';
import { AppDataSource } from './data-source';
async function handleDatabaseOperation() {
try {
const user = await AppDataSource.getRepository(User).findOne({
where: { email: 'test@example.com' },
});
return user;
} catch (error) {
if (error instanceof QueryFailedError) {
// Database-specific errors
const driverError = error.driverError;
// Unique constraint violation
if (driverError.code === '23505') {
throw new Error('Email already exists');
}
// Foreign key violation
if (driverError.code === '23503') {
throw new Error('Referenced record not found');
}
// Not null violation
if (driverError.code === '23502') {
throw new Error('Required field is missing');
}
// Log the error
console.error('Query failed:', error.message);
throw new Error('Database operation failed');
}
// Re-throw other errors
throw error;
}
}

import 'reflect-metadata';
import { AppDataSource } from './data-source';
async function bootstrap() {
try {
await AppDataSource.initialize();
console.log('Database connected');
// Start your application...
} catch (error) {
console.error('Failed to connect to database:', error);
process.exit(1);
}
}
// Graceful shutdown handlers
const gracefulShutdown = async (signal: string) => {
console.log(`\n${signal} received. Shutting down gracefully...`);
try {
if (AppDataSource.isInitialized) {
await AppDataSource.destroy();
console.log('Database connection closed');
}
process.exit(0);
} catch (error) {
console.error('Error during shutdown:', error);
process.exit(1);
}
};
// Register shutdown handlers
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
gracefulShutdown('uncaughtException');
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason);
gracefulShutdown('unhandledRejection');
});
bootstrap();

DataSource Key Points
+------------------------------------------------------------------+
| |
| Concept | Description |
| ---------------------|---------------------------------------- |
| DataSource | Main connection configuration object |
| initialize() | Establish database connection |
| destroy() | Close database connection |
| manager | Entity Manager for operations |
| getRepository() | Get repository for entity |
| transaction() | Run operations in transaction |
| query() | Execute raw SQL queries |
| isInitialized | Check if connection is active |
| |
+------------------------------------------------------------------+

Chapter 6: Entity Definition & Decorators


Last Updated: February 2026