Entity
Connecting to the database is just the first step. To actually store and retrieve data, we need to define what our data looks like — its structure, column types, and constraints. In TypeORM, this is done through Entities.
What is an Entity?
An Entity is a TypeScript class decorated with @Entity(). Each instance of the class corresponds to a row in the database table. Each property of the class (decorated with @Column) corresponds to a column.
It is the TypeORM equivalent of a Mongoose Schema + Model combined into one.
| Mongoose | TypeORM |
|---|---|
new mongoose.Schema({ ... }) | Class properties + @Column() |
mongoose.model('Name', schema) | @Entity() on the class |
| Schema field options | Column decorator options |
Creating an Entity
Here's a simple entity for a Person:
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
} from "typeorm";
@Entity()
export class Person {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
age: number;
@Column({ unique: true })
email: string;
@CreateDateColumn()
createdAt: Date;
}
Let's break it down:
@Entity(): Tells TypeORM this class is a database table. The table name defaults to the class name in lowercase (person). You can override it:@Entity("people").@PrimaryGeneratedColumn(): Creates an auto-incrementing integer primary key column calledid. This is analogous to MongoDB's_id.@Column(): Marks a class property as a table column. TypeORM infers the column type from the TypeScript type (string→varchar,number→integer,boolean→boolean).@CreateDateColumn(): Automatically sets the column to the current timestamp when a row is inserted. TypeORM also provides@UpdateDateColumn()for automatic update timestamps.
Column Options
You can pass an options object to @Column() to configure the column:
@Column({ type: "varchar", length: 100, nullable: false, default: "Unknown" })
name: string;
| Option | Description | Example |
|---|---|---|
type | The database column type. Usually inferred automatically. | "varchar", "int", "text" |
length | Max length for string columns. | length: 255 |
nullable | Whether the column allows NULL. Defaults to false. | nullable: true |
unique | Adds a unique constraint to the column. | unique: true |
default | Default value if none is provided. | default: "Pakistan" |
select | If false, the column is excluded from SELECT queries. | select: false (useful for passwords) |
enum | Restricts the column to a set of allowed string values. | enum: ["male", "female"] |
Column Types
TypeORM infers the SQL type from the TypeScript type automatically in most cases. Here's a reference:
| TypeScript Type | Inferred SQL Type |
|---|---|
string | varchar |
number | integer |
boolean | boolean |
Date | timestamp |
string[] | simple-array |
For full control, pass the type explicitly:
@Column({ type: "text" })
bio: string;
@Column({ type: "decimal", precision: 10, scale: 2 })
price: number;
@Column({ type: "enum", enum: ["admin", "user", "guest"], default: "user" })
role: string;
Special Column Decorators
| Decorator | Purpose |
|---|---|
@PrimaryGeneratedColumn() | Auto-incrementing integer primary key |
@PrimaryGeneratedColumn("uuid") | UUID primary key (automatically generated) |
@CreateDateColumn() | Set to NOW() on insert, never updated |
@UpdateDateColumn() | Set to NOW() on every update |
@DeleteDateColumn() | Enables soft deletes — stores deletion timestamp |
@VersionColumn() | Auto-increments on each update (optimistic locking) |
Nullable Columns
By default, TypeORM marks columns as NOT NULL. If a column is optional, mark it as nullable:
@Column({ nullable: true })
phone: string | null;
A Complete Entity Example
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from "typeorm";
@Entity("people")
export class Person {
@PrimaryGeneratedColumn()
id: number;
@Column({ length: 100 })
name: string;
@Column()
age: number;
@Column({ unique: true })
email: string;
@Column({ nullable: true })
phone: string | null;
@Column({ default: true })
isAlive: boolean;
@Column({ type: "enum", enum: ["male", "female", "other"] })
gender: string;
@Column({ select: false })
password: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
Relations Between Entities
Just like Mongoose uses ref to link documents, TypeORM uses relation decorators to link entities. These become foreign key columns in the database.
ManyToOne / OneToMany
A post belongs to one user. A user can have many posts.
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from "typeorm";
import { Post } from "./Post";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(() => Post, (post) => post.author)
posts: Post[];
}
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from "typeorm";
import { User } from "./User";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@ManyToOne(() => User, (user) => user.posts)
author: User;
}
TypeORM will automatically add an authorId foreign key column to the post table.
@OneToMany is always defined alongside a matching @ManyToOne on the other side. The table that holds the foreign key column is always the @ManyToOne side.
Registering the Entity
Make sure your entity file matches the glob pattern in your DataSource configuration:
entities: ["src/entities/*.ts"],
With synchronize: true enabled, TypeORM will automatically create the table when the app starts.
Conclusion
In this doc, we learned how to define an Entity in TypeORM using decorators. An Entity maps a TypeScript class to a PostgreSQL table. We covered column types, options, special decorators, and how to define relations between entities.
In the next doc, we'll learn how to perform CRUD operations using the Repository API.