0
0
NestJSframework~15 mins

Entity definition in NestJS - Deep Dive

Choose your learning style9 modes available
Overview - Entity definition
What is it?
An entity in NestJS is a class that represents a table in a database. It defines the structure of the data, including columns and their types. Entities help NestJS understand how to store and retrieve data from the database. They are the foundation for working with databases in NestJS applications.
Why it matters
Without entities, NestJS would not know how to organize or manage data in a database. Entities solve the problem of mapping between code and database tables, making data handling easier and less error-prone. Without this concept, developers would have to write complex database queries manually, increasing mistakes and slowing development.
Where it fits
Before learning entity definition, you should understand basic TypeScript classes and decorators. After mastering entities, you can learn about repositories and services to perform database operations. This topic fits into the data management layer of a NestJS application.
Mental Model
Core Idea
An entity is a blueprint class that tells NestJS how to store and retrieve data as rows and columns in a database table.
Think of it like...
Think of an entity like a blueprint for a filing cabinet drawer: it defines what kind of files (data) go inside and how they are labeled (columns), so you can easily find and organize information.
┌───────────────┐
│   Entity      │
│───────────────│
│ Class Name    │
│ ┌───────────┐ │
│ │ Properties│ │
│ │ (Columns) │ │
│ └───────────┘ │
└─────┬─────────┘
      │
      ▼
┌───────────────┐
│ Database Table│
│───────────────│
│ Rows of Data  │
│ Columns match │
│ entity fields │
└───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding Basic Entity Classes
🤔
Concept: Learn what an entity class is and how it represents a database table.
In NestJS, an entity is a TypeScript class decorated with @Entity(). Each property in the class represents a column in the database. For example: import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() email: string; } This defines a User entity with id, name, and email columns.
Result
NestJS knows to create a 'User' table with columns 'id', 'name', and 'email' in the database.
Understanding that an entity is just a class with special decorators helps you see how NestJS connects code to the database structure.
2
FoundationUsing Decorators to Define Columns
🤔
Concept: Learn how decorators specify column types and behaviors in entities.
Decorators like @PrimaryGeneratedColumn() and @Column() tell NestJS and TypeORM how to treat each property. For example, @PrimaryGeneratedColumn() marks a property as the primary key that auto-increments. @Column() marks a regular column. You can also specify column types and options: @Column({ type: 'varchar', length: 100, unique: true }) email: string; This means the email column is a string with max length 100 and must be unique.
Result
The database table columns have the correct types and constraints as defined in the entity.
Knowing decorators control how properties map to database columns lets you customize your data structure precisely.
3
IntermediateDefining Relationships Between Entities
🤔Before reading on: do you think entities can only represent single tables, or can they also describe connections between tables? Commit to your answer.
Concept: Entities can define relationships like one-to-many or many-to-one between tables using special decorators.
NestJS with TypeORM allows entities to link to each other. For example, a User entity can have many Posts: import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany } from 'typeorm'; @Entity() export class Post { @PrimaryGeneratedColumn() id: number; @Column() title: string; @ManyToOne(() => User, user => user.posts) user: User; } @Entity() export class User { @PrimaryGeneratedColumn() id: number; @OneToMany(() => Post, post => post.user) posts: Post[]; } This creates a foreign key relationship in the database.
Result
The database tables are linked, allowing queries to fetch related data easily.
Understanding entity relationships unlocks powerful ways to model real-world data connections in your app.
4
IntermediateCustomizing Column Options and Types
🤔Before reading on: do you think all columns are simple text or numbers, or can you customize their behavior and storage? Commit to your answer.
Concept: You can customize columns with options like nullable, default values, and specific database types.
For example: @Column({ type: 'int', nullable: true, default: 0 }) age: number; This means the age column can be empty (null) and defaults to 0 if not set. You can also use types like 'date', 'boolean', or 'json'. This helps match your data needs exactly.
Result
The database columns behave exactly as you want, supporting optional fields and defaults.
Knowing how to customize columns prevents data errors and matches your app's logic to the database.
5
AdvancedUsing Inheritance and Abstract Entities
🤔Before reading on: do you think entities must always be standalone, or can they share common fields through inheritance? Commit to your answer.
Concept: Entities can inherit from base classes to share common columns and logic.
You can create an abstract base entity: import { PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm'; export abstract class BaseEntity { @PrimaryGeneratedColumn() id: number; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; } Then extend it: import { Entity, Column } from 'typeorm'; @Entity() export class User extends BaseEntity { @Column() name: string; } This avoids repeating common fields in every entity.
Result
Entities share common columns automatically, reducing code duplication.
Understanding inheritance in entities helps build cleaner, maintainable data models.
6
ExpertEntity Lifecycle and Hooks in NestJS
🤔Before reading on: do you think entities are passive data holders, or can they react to events like saving or updating? Commit to your answer.
Concept: Entities can have lifecycle hooks that run code before or after database actions.
TypeORM supports hooks like @BeforeInsert, @AfterUpdate: import { Entity, Column, PrimaryGeneratedColumn, BeforeInsert } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() createdAt: Date; @BeforeInsert() setCreatedAt() { this.createdAt = new Date(); } } These hooks let you add logic automatically during entity changes.
Result
Entities can enforce rules or update fields automatically during database operations.
Knowing entity hooks lets you embed business logic close to data, improving consistency and reducing errors.
Under the Hood
NestJS uses TypeORM under the hood to map entity classes to database tables. When the app starts, TypeORM reads entity decorators and builds a metadata model. It generates SQL commands to create or update tables accordingly. When you save or query entities, TypeORM translates these actions into SQL queries. Decorators add metadata to class properties, telling TypeORM how to handle each column and relationship.
Why designed this way?
This design uses decorators and classes to keep database logic close to code, making it easier to maintain and understand. It avoids writing raw SQL by hand, reducing errors and speeding development. The metadata approach allows flexible customization and supports many database types. Alternatives like raw queries or XML mappings were more complex and error-prone.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Entity Class  │──────▶│ Metadata Store│──────▶│ SQL Generator │
│ (with Decorators)│     │ (Decorators info)│    │ (creates SQL) │
└───────────────┘       └───────────────┘       └───────────────┘
        │                        │                      │
        ▼                        ▼                      ▼
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Application   │       │ Database      │◀──────│ SQL Queries   │
│ Code          │       │ Tables        │       │ Execution    │
└───────────────┘       └───────────────┘       └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think an entity class must always match the database table name exactly? Commit to yes or no.
Common Belief:Many believe the entity class name must exactly match the database table name.
Tap to reveal reality
Reality:You can customize the table name with @Entity('custom_table_name'). The class name and table name can differ.
Why it matters:Assuming names must match can cause confusion and errors when integrating with existing databases or naming conventions.
Quick: Do you think entity properties must always be public to work with the database? Commit to yes or no.
Common Belief:Some think entity properties must be public to be saved or loaded.
Tap to reveal reality
Reality:Properties can be private or protected with getters/setters, but you must configure TypeORM accordingly. By default, public properties are easier.
Why it matters:Misunderstanding this limits design choices and can cause bugs when trying to encapsulate data.
Quick: Do you think entities automatically validate data types before saving? Commit to yes or no.
Common Belief:People often believe entities validate data types automatically before saving to the database.
Tap to reveal reality
Reality:Entities define structure but do not validate data values. Validation must be done separately using validation libraries or manual checks.
Why it matters:Relying on entities alone for validation can lead to invalid data stored in the database.
Quick: Do you think entity lifecycle hooks run in any order you want? Commit to yes or no.
Common Belief:Some assume lifecycle hooks like @BeforeInsert and @AfterInsert run in any order or multiple times.
Tap to reveal reality
Reality:Hooks run in a defined order and only once per event. Misusing them can cause unexpected behavior.
Why it matters:Misunderstanding hook order can cause bugs in data processing or inconsistent state.
Expert Zone
1
Entities can be used with multiple database connections by specifying connection names, allowing complex multi-database apps.
2
Lazy loading relations with Promise properties can improve performance but requires careful handling to avoid unexpected database calls.
3
Using embedded entities allows grouping related columns inside one entity without creating separate tables, simplifying complex schemas.
When NOT to use
Entity definitions are not suitable when you need raw SQL performance optimizations or complex queries that ORM cannot express well. In such cases, use query builders or raw SQL queries directly.
Production Patterns
In production, entities are combined with repositories and services to separate concerns. Entities define data shape, repositories handle database queries, and services contain business logic. Entities often use migrations to safely evolve database schemas over time.
Connections
Object-Relational Mapping (ORM)
Entity definition is a core part of ORM, which maps objects in code to database tables.
Understanding entities helps grasp how ORMs automate database interactions, reducing manual SQL work.
Database Normalization
Entities and their relationships reflect normalized database design principles.
Knowing normalization helps design entities that avoid data duplication and maintain integrity.
Class Design in Object-Oriented Programming
Entities are specialized classes with metadata for persistence.
Understanding OOP concepts like inheritance and encapsulation improves entity design and reuse.
Common Pitfalls
#1Defining entity properties without decorators causes them to be ignored by the ORM.
Wrong approach:export class User { id: number; name: string; } // No @PrimaryGeneratedColumn or @Column decorators
Correct approach:import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'; @Entity() export class User { @PrimaryGeneratedColumn() id: number; @Column() name: string; }
Root cause:Missing decorators means TypeORM does not know which properties map to database columns.
#2Using the same entity instance across multiple requests causes unexpected data sharing.
Wrong approach:const user = new User(); // Reusing 'user' instance globally in app
Correct approach:Create new entity instances per request or operation to avoid shared mutable state.
Root cause:Entities are plain objects; sharing instances leads to data leaks and bugs.
#3Assuming entity changes are saved automatically without calling save methods.
Wrong approach:user.name = 'New Name'; // No repository.save(user) call
Correct approach:user.name = 'New Name'; await repository.save(user);
Root cause:Entities are disconnected from the database until explicitly saved.
Key Takeaways
Entities in NestJS are classes that define how data is stored in database tables using decorators.
Decorators specify column types, keys, and relationships, allowing precise control over the database schema.
Entities can relate to each other, enabling complex data models that reflect real-world connections.
Advanced features like inheritance and lifecycle hooks help write cleaner, more maintainable data code.
Understanding entities deeply helps you build robust, efficient, and scalable database-backed applications.