Entity_definition
Chapter 6: Entity Definition & Decorators
Section titled “Chapter 6: Entity Definition & Decorators”Understanding TypeORM Entities
Section titled “Understanding TypeORM Entities”6.1 What is an Entity?
Section titled “6.1 What is an Entity?”An entity is a TypeScript class that maps to a database table. TypeORM uses decorators to define the mapping.
Entity to Table Mapping ================================================================================
TypeScript Entity Database Table +------------------------+ +------------------------+ | @Entity('users') | | TABLE users | | class User { | maps | ---------------------- | | @PrimaryGenerated... | -----> | id SERIAL PK | | id: number; | | name VARCHAR(100) | | | | email VARCHAR(255) | | @Column() | | active BOOLEAN | | name: string; | | created TIMESTAMP | | | +------------------------+ | @Column() | | | | email: string; | | | | | | | | @Column() | | | | active: boolean; | | | | } | | | +------------------------+ +------------------------+
================================================================================6.2 Entity Decorators
Section titled “6.2 Entity Decorators”@Entity() Decorator
Section titled “@Entity() Decorator”The @Entity() decorator marks a class as a database entity.
import { Entity } from 'typeorm';
// Basic usage - table name = class name (lowercase)@Entity()class User { // Creates table named "user"}
// Custom table name@Entity('users')class User { // Creates table named "users"}
// With schema@Entity('users', { schema: 'public' })class User { // Creates table in specific schema}
// With database (for multi-database)@Entity('users', { database: 'secondary' })class User { // Creates table in specific database}
// Without synchronization@Entity('users', { synchronize: false })class User { // Table won't be auto-synced}Entity Options
Section titled “Entity Options” @Entity() Options +------------------------------------------------------------------+ | | | @Entity(name?: string, options?: EntityOptions) | | | | Options: | | +----------------------------------------------------------+ | | | | | | | name: string | Table name | | | | database: string | Database name | | | | schema: string | Schema name | | | | synchronize: boolean | Auto-sync (default: true) | | | | orderBy: object | Default ordering | | | | engine: string | Database engine | | | | database: string | Database selection | | | | | | | +----------------------------------------------------------+ | | | +------------------------------------------------------------------+6.3 Column Decorators
Section titled “6.3 Column Decorators”@PrimaryColumn()
Section titled “@PrimaryColumn()”Defines a primary key column.
import { Entity, PrimaryColumn } from 'typeorm';
@Entity('users')class User { @PrimaryColumn() id: string;
// Generated SQL: // id VARCHAR(255) PRIMARY KEY}@PrimaryGeneratedColumn()
Section titled “@PrimaryGeneratedColumn()”Defines an auto-generated primary key.
import { Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity('users')class User { // Auto-increment integer @PrimaryGeneratedColumn() id: number; // Generated SQL: id SERIAL PRIMARY KEY
// UUID @PrimaryGeneratedColumn('uuid') id: string; // Generated SQL: id UUID PRIMARY KEY DEFAULT uuid_generate_v4()
// Identity (PostgreSQL 10+) @PrimaryGeneratedColumn('identity') id: number; // Generated SQL: id GENERATED BY DEFAULT AS IDENTITY}@Column()
Section titled “@Column()”Defines a regular column.
import { Entity, Column } from 'typeorm';
@Entity('users')class User { @Column() name: string; // Generated SQL: name VARCHAR(255)
@Column({ type: 'text' }) bio: string; // Generated SQL: bio TEXT
@Column({ length: 100 }) shortName: string; // Generated SQL: shortName VARCHAR(100)
@Column({ unique: true }) email: string; // Generated SQL: email VARCHAR(255) UNIQUE
@Column({ nullable: true }) nickname: string; // Generated SQL: nickname VARCHAR(255) NULL
@Column({ default: 'user' }) role: string; // Generated SQL: role VARCHAR(255) DEFAULT 'user'
@Column({ select: false }) password: string; // Column excluded from default SELECT queries}6.4 Column Types
Section titled “6.4 Column Types”String Types
Section titled “String Types”@Entity('posts')class Post { // VARCHAR (default for string) @Column() title: string; // SQL: title VARCHAR(255)
// VARCHAR with length @Column({ length: 100 }) shortTitle: string; // SQL: shortTitle VARCHAR(100)
// TEXT @Column({ type: 'text' }) content: string; // SQL: content TEXT
// CHAR (fixed length) @Column({ type: 'char', length: 2 }) countryCode: string; // SQL: countryCode CHAR(2)
// VARCHAR array (PostgreSQL) @Column({ type: 'varchar', array: true }) tags: string[]; // SQL: tags VARCHAR[]}Number Types
Section titled “Number Types”@Entity('products')class Product { // INTEGER (default for number) @Column() quantity: number; // SQL: quantity INTEGER
// INT @Column({ type: 'int' }) stock: number; // SQL: stock INT
// BIGINT @Column({ type: 'bigint' }) largeNumber: number; // SQL: largeNumber BIGINT
// SMALLINT @Column({ type: 'smallint' }) smallNumber: number; // SQL: smallNumber SMALLINT
// DECIMAL @Column({ type: 'decimal', precision: 10, scale: 2 }) price: number; // SQL: price DECIMAL(10, 2)
// FLOAT @Column({ type: 'float' }) rating: number; // SQL: rating FLOAT
// DOUBLE @Column({ type: 'double' }) preciseRating: number; // SQL: preciseRating DOUBLE
// REAL @Column({ type: 'real' }) anotherNumber: number; // SQL: anotherNumber REAL}Boolean Type
Section titled “Boolean Type”@Entity('users')class User { @Column() isActive: boolean; // SQL: isActive BOOLEAN DEFAULT false
@Column({ default: true }) emailVerified: boolean; // SQL: emailVerified BOOLEAN DEFAULT true}Date Types
Section titled “Date Types”@Entity('events')class Event { // TIMESTAMP (default for Date) @Column() createdAt: Date; // SQL: createdAt TIMESTAMP
// DATE @Column({ type: 'date' }) birthDate: Date; // SQL: birthDate DATE
// TIME @Column({ type: 'time' }) startTime: Date; // SQL: startTime TIME
// DATETIME (MySQL) @Column({ type: 'datetime' }) updatedAt: Date; // SQL: updatedAt DATETIME
// TIMESTAMP WITH TIMEZONE @Column({ type: 'timestamptz' }) eventTime: Date; // SQL: eventTime TIMESTAMPTZ}JSON Types
Section titled “JSON Types”@Entity('users')class User { // JSON @Column({ type: 'json' }) preferences: object; // SQL: preferences JSON
// JSONB (PostgreSQL - binary JSON, faster) @Column({ type: 'jsonb' }) metadata: Record<string, any>; // SQL: metadata JSONB
// Simple JSON @Column({ type: 'simple-json' }) tags: string[]; // SQL: tags TEXT (stored as JSON string)}Array Types (PostgreSQL)
Section titled “Array Types (PostgreSQL)”@Entity('posts')class Post { // Integer array @Column({ type: 'int', array: true }) ratings: number[]; // SQL: ratings INT[]
// Text array @Column({ type: 'text', array: true }) tags: string[]; // SQL: tags TEXT[]
// UUID array @Column({ type: 'uuid', array: true }) relatedIds: string[]; // SQL: relatedIds UUID[]}Enum Types
Section titled “Enum Types”enum UserRole { ADMIN = 'admin', USER = 'user', GUEST = 'guest',}
enum UserStatus { ACTIVE, INACTIVE, PENDING,}
@Entity('users')class User { // String enum @Column({ type: 'enum', enum: UserRole, default: UserRole.USER, }) role: UserRole; // SQL: role ENUM('admin', 'user', 'guest') DEFAULT 'user'
// Numeric enum @Column({ type: 'enum', enum: UserStatus, default: UserStatus.PENDING, }) status: UserStatus; // SQL: status INT DEFAULT 2 (enum values as numbers)
// Enum with custom name @Column({ type: 'enum', enum: UserRole, enumName: 'user_role_enum', }) customRole: UserRole; // SQL: Creates custom enum type in PostgreSQL}6.5 Special Column Types
Section titled “6.5 Special Column Types”@CreateDateColumn()
Section titled “@CreateDateColumn()”Automatically sets the date when entity is created.
@Entity('users')class User { @CreateDateColumn() createdAt: Date; // Automatically set to current date on INSERT}@UpdateDateColumn()
Section titled “@UpdateDateColumn()”Automatically updates the date when entity is updated.
@Entity('users')class User { @UpdateDateColumn() updatedAt: Date; // Automatically updated on each UPDATE}@DeleteDateColumn()
Section titled “@DeleteDateColumn()”Used for soft deletes.
@Entity('users')class User { @DeleteDateColumn() deletedAt: Date; // Set to current date when entity is "deleted" // NULL means not deleted}@VersionColumn()
Section titled “@VersionColumn()”Used for optimistic locking.
@Entity('users')class User { @VersionColumn() version: number; // Automatically incremented on each UPDATE}6.6 Column Options
Section titled “6.6 Column Options” Complete Column Options +------------------------------------------------------------------+ | | | @Column({ | | type: 'varchar', // Column type | | length: 255, // String length | | precision: 10, // Numeric precision | | scale: 2, // Numeric scale | | nullable: false, // Allow NULL? | | default: 'value', // Default value | | unique: false, // Unique constraint | | select: true, // Include in SELECT? | | insert: true, // Include in INSERT? | | update: true, // Include in UPDATE? | | readonly: false, // Never update? | | comment: 'Description', // Column comment | | array: false, // Is array? (PostgreSQL) | | enum: [], // Enum values | | enumName: '', // Enum type name (PostgreSQL) | | transformer: { // Value transformer | | to: (value) => value, | | from: (value) => value, | | }, | | name: 'column_name', // Custom column name | | primary: false, // Is primary key? | | generated: false, // Auto-generate? | | collation: 'utf8mb4', // Collation | | charset: 'utf8mb4', // Character set | | spatialFeatureType: '', // Spatial type | | srid: 0, // Spatial reference ID | | }) | | | +------------------------------------------------------------------+6.7 Complete Entity Example
Section titled “6.7 Complete Entity Example”import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, DeleteDateColumn, Index,} from 'typeorm';
enum UserRole { ADMIN = 'admin', USER = 'user', MODERATOR = 'moderator',}
@Entity('users')@Index(['email'], { unique: true }) // Unique index on email@Index(['firstName', 'lastName']) // Composite indexexport class User { // Primary Key @PrimaryGeneratedColumn('uuid') id: string;
// Basic columns @Column({ length: 50 }) firstName: string;
@Column({ length: 50 }) lastName: string;
@Column({ unique: true }) email: string;
@Column({ select: false }) // Excluded from default SELECT password: string;
// With default value @Column({ default: true }) isActive: boolean;
// Enum column @Column({ type: 'enum', enum: UserRole, default: UserRole.USER, }) role: UserRole;
// Nullable column @Column({ type: 'text', nullable: true }) bio: string;
// JSON column @Column({ type: 'jsonb', nullable: true }) preferences: Record<string, any>;
// Date columns @CreateDateColumn({ name: 'created_at' }) createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' }) updatedAt: Date;
// Soft delete @DeleteDateColumn({ name: 'deleted_at', nullable: true }) deletedAt: Date;
// Computed property (not a column) get fullName(): string { return `${this.firstName} ${this.lastName}`; }}6.8 Entity Inheritance
Section titled “6.8 Entity Inheritance”Single Table Inheritance
Section titled “Single Table Inheritance” Single Table Inheritance +------------------------------------------------------------------+ | | | All entities stored in ONE table with discriminator column | | | | +----------------------------------------------------------+ | | | content_items | | | |----------------------------------------------------------| | | | id | type | title | content | duration | url | | | |----|----------|----------|----------|----------|---------| | | | 1 | article | News | Text... | NULL | NULL | | | | 2 | video | Tutorial | NULL | 120 | http:// | | | | 3 | article | Guide | Text... | NULL | NULL | | | +----------------------------------------------------------+ | | | +------------------------------------------------------------------+import { Entity, Column, TableInheritance, ChildEntity } from 'typeorm';
// Base entity@Entity('content_items')@TableInheritance({ column: { name: 'type', type: 'varchar', length: 20 },})export abstract class ContentItem { @PrimaryGeneratedColumn() id: number;
@Column() title: string;}
// Child entities@ChildEntity('article')export class Article extends ContentItem { @Column() content: string;}
@ChildEntity('video')export class Video extends ContentItem { @Column() duration: number;
@Column() url: string;}Class Table Inheritance
Section titled “Class Table Inheritance”import { Entity, Column, TableInheritance, ChildEntity, PrimaryGeneratedColumn } from 'typeorm';
// Base entity@Entity()@TableInheritance({ pattern: 'class-table',})export abstract class Person { @PrimaryGeneratedColumn() id: number;
@Column() name: string;}
// Child entities (each has own table)@ChildEntity()@Entity('employees')export class Employee extends Person { @Column() salary: number;
@Column() department: string;}
@ChildEntity()@Entity('customers')export class Customer extends Person { @Column() email: string;
@Column() totalPurchases: number;}Embedded Entities
Section titled “Embedded Entities”import { Entity, Column, Embedded } from 'typeorm';
// Embedded entity (not a table)export class Address { @Column() street: string;
@Column() city: string;
@Column() country: string;
@Column() postalCode: string;}
export class Profile { @Column() bio: string;
@Column() avatar: string;}
// Main entity with embedded entities@Entity('users')export class User { @PrimaryGeneratedColumn() id: number;
@Column() name: string;
// Embedded entity - columns prefixed with 'address_' @Embedded(() => Address, { prefix: 'address' }) address: Address;
// Embedded entity - columns prefixed with 'profile_' @Embedded(() => Profile, { prefix: 'profile' }) profile: Profile;}
// Generated table:// CREATE TABLE users (// id SERIAL PRIMARY KEY,// name VARCHAR(255),// address_street VARCHAR(255),// address_city VARCHAR(255),// address_country VARCHAR(255),// address_postalCode VARCHAR(255),// profile_bio VARCHAR(255),// profile_avatar VARCHAR(255)// );6.9 Indexes
Section titled “6.9 Indexes”@Index() Decorator
Section titled “@Index() Decorator”import { Entity, Index, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('users')@Index(['firstName', 'lastName']) // Composite index@Index(['email'], { unique: true }) // Unique indexexport class User { @PrimaryGeneratedColumn() id: number;
@Column() firstName: string;
@Column() lastName: string;
@Column() email: string;
@Index() // Column-level index @Column() username: string;}Index Options
Section titled “Index Options”@Entity('posts')@Index(['title', 'content'], { synchronize: true, // Auto-create index name: 'IDX_POST_SEARCH', // Custom index name unique: false, // Unique constraint spatial: false, // Spatial index fulltext: true, // Full-text index (MySQL) where: 'deleted_at IS NULL', // Partial index (PostgreSQL)})export class Post { @PrimaryGeneratedColumn() id: number;
@Column() title: string;
@Column({ type: 'text' }) content: string;
@DeleteDateColumn() deletedAt: Date;}6.10 Naming Strategies
Section titled “6.10 Naming Strategies”TypeORM uses naming strategies to convert entity/property names to table/column names.
// Snake case naming strategyimport { DefaultNamingStrategy, NamingStrategyInterface } from 'typeorm';import { camelCase, snakeCase } from 'typeorm/util/StringUtils';
export class SnakeNamingStrategy extends DefaultNamingStrategy implements NamingStrategyInterface{ tableName(className: string, customName: string): string { return customName || snakeCase(className); }
columnName( propertyName: string, customName: string, embeddedPrefix: string[] ): string { return snakeCase(embeddedPrefix.join('_')) + (customName || snakeCase(propertyName)); }
relationName(propertyName: string): string { return snakeCase(propertyName); }}
// Usage in DataSourceimport { DataSource } from 'typeorm';import { SnakeNamingStrategy } from './naming-strategies/snake-naming.strategy';
export const AppDataSource = new DataSource({ // ... other options namingStrategy: new SnakeNamingStrategy(),});Naming Strategy Results
Section titled “Naming Strategy Results” Naming Strategy Comparison +------------------------------------------------------------------+ | | | TypeScript Name | Default Strategy | Snake Strategy | | ---------------------|------------------|---------------------- | | class UserAccount | useraccount | user_account | | firstName | firstName | first_name | | lastName | lastName | last_name | | createdAt | createdAt | created_at | | isActive | isActive | is_active | | | +------------------------------------------------------------------+6.11 Entity Metadata
Section titled “6.11 Entity Metadata”import { getMetadataArgsStorage } from 'typeorm';
// Get all entity metadataconst metadata = getMetadataArgsStorage();
// Get tablesconsole.log(metadata.tables);// Output: [{ target: User, name: 'users', ... }]
// Get columnsconsole.log(metadata.columns);// Output: [{ target: User, propertyName: 'firstName', ... }]
// Get indicesconsole.log(metadata.indices);// Output: [{ target: User, columns: ['email'], ... }]6.12 Summary
Section titled “6.12 Summary” Entity Decorators Summary +------------------------------------------------------------------+ | | | Decorator | Purpose | | ------------------------|-------------------------------------- | | @Entity() | Mark class as database table | | @PrimaryColumn() | Primary key column | | @PrimaryGeneratedColumn()| Auto-generated primary key | | @Column() | Regular column | | @CreateDateColumn() | Auto-set on create | | @UpdateDateColumn() | Auto-update on modify | | @DeleteDateColumn() | Soft delete timestamp | | @VersionColumn() | Optimistic locking version | | @Index() | Create index | | @Embedded() | Embed another entity | | @TableInheritance() | Enable inheritance | | @ChildEntity() | Mark as child entity | | | +------------------------------------------------------------------+Next Chapter
Section titled “Next Chapter”Chapter 7: Column Types & Options
Last Updated: February 2026