Skip to main content

Command Palette

Search for a command to run...

TypeORM TypeScript: ORM for TypeScript Apps

Updated
4 min readView as Markdown
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

TypeORM: TypeScript ORM for Modern Applications

TypeORM is a powerful Object-Relational Mapping (ORM) library for TypeScript and JavaScript that simplifies database interactions in your applications. Here's a comprehensive guide:

What is TypeORM?

TypeORM is an ORM that allows you to work with databases using TypeScript classes and decorators instead of writing raw SQL queries. It supports multiple databases including PostgreSQL, MySQL, SQLite, MongoDB, and more.

Key Features

  • Decorator-based: Uses TypeScript decorators for elegant entity definitions
  • Multiple Database Support: Works with PostgreSQL, MySQL, MariaDB, SQLite, Oracle, SQL Server, and MongoDB
  • Query Builder: Fluent API for building complex queries
  • Relations: Supports one-to-one, one-to-many, and many-to-many relationships
  • Migrations: Built-in migration system for schema management
  • Active Record & Data Mapper: Two architectural patterns supported
  • Lazy Relations: Load related data on demand
  • Transaction Support: Handle complex multi-step operations safely

Installation

npm install typeorm reflect-metadata
npm install --save-dev @types/node typescript

Basic Setup

1. Configure TypeScript

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

2. Create Data Source

import "reflect-metadata";
import { DataSource } from "typeorm";
import { User } from "./entities/User";
import { Post } from "./entities/Post";

export const AppDataSource = new DataSource({
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "postgres",
  password: "password",
  database: "typeorm_db",
  synchronize: true,
  logging: false,
  entities: [User, Post],
  migrations: ["src/migrations/*.ts"],
  subscribers: ["src/subscribers/*.ts"],
});

Defining Entities

Simple Entity

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ unique: true })
  email: string;

  @Column({ default: true })
  isActive: boolean;

  @Column({ type: "timestamp", default: () => "CURRENT_TIMESTAMP" })
  createdAt: Date;
}

Entity with Relations

import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  OneToMany,
  ManyToOne,
  JoinColumn,
} from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @OneToMany(() => Post, (post) => post.author)
  posts: Post[];
}

@Entity()
export class Post {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  content: string;

  @ManyToOne(() => User, (user) => user.posts)
  @JoinColumn({ name: "authorId" })
  author: User;

  @Column()
  authorId: number;
}

Many-to-Many Relation

import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";

@Entity()
export class Student {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @ManyToMany(() => Course)
  @JoinTable()
  courses: Course[];
}

@Entity()
export class Course {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @ManyToMany(() => Student, (student) => student.courses)
  students: Student[];
}

CRUD Operations

Using Repository Pattern

import { AppDataSource } from "./data-source";
import { User } from "./entities/User";

// Initialize connection
await AppDataSource.initialize();

const userRepository = AppDataSource.getRepository(User);

// Create
const user = userRepository.create({
  firstName: "John",
  lastName: "Doe",
  email: "john@example.com",
});
await userRepository.save(user);

// Read
const foundUser = await userRepository.findOne({
  where: { id: 1 },
});

// Update
user.firstName = "Jane";
await userRepository.save(user);

// Delete
await userRepository.remove(user);

Query Builder

// Complex queries with Query Builder
const users = await userRepository
  .createQueryBuilder("user")
  .leftJoinAndSelect("user.posts", "post")
  .where("user.isActive = :isActive", { isActive: true })
  .andWhere("post.createdAt > :date", { date: new Date("2024-01-01") })
  .orderBy("user.createdAt", "DESC")
  .take(10)
  .skip(0)
  .getMany();

// Aggregation
const count = await userRepository
  .createQueryBuilder("user")
  .select("COUNT(user.id)", "count")
  .getRawOne();

Migrations

# Generate migration
npx typeorm migration:generate src/migrations/InitialMigration

# Run migrations
npx typeorm migration:run

# Revert migration
npx typeorm migration:revert

Best Practices

  1. Use Repositories: Always use repositories instead of raw queries
  2. Lazy Load Relations: Use lazy: true for large datasets
  3. Validation: Combine with class-validator for data validation
  4. Error Handling: Wrap database operations in try-catch blocks
  5. Connection Pooling: Configure appropriate pool sizes
  6. Indexes: Add indexes to frequently queried columns
  7. Transactions: Use transactions for data consistency

Integration with Express

import express from "express";
import { AppDataSource } from "./data-source";

const app = express();

AppDataSource.initialize()
  .then(() => {
    app.listen(3000, () => {
      console.log("Server running on port 3000");
    });
  })
  .catch((error) => console.log(error));

app.get("/users", async (req, res) => {
  const userRepository = AppDataSource.getRepository(User);
  const users = await userRepository.find();
  res.json(users);
});

Conclusion

TypeORM provides a robust, type-safe way to interact with databases in TypeScript applications. Its decorator-based approach, powerful query builder, and support for multiple databases make it an excellent choice for modern backend development.