Skip to main content
Get started with NestJS CRUD by building a complete CRUD API for managing users. This guide will walk you through creating an entity, service, controller, and testing your API.

Prerequisites

Make sure you have completed the installation steps and have a NestJS project set up with TypeORM and NestJS CRUD installed.

Create your first CRUD API

1

Create an entity

Create a TypeORM entity to define your data model. Add validation decorators from class-validator:
User.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { IsString, IsEmail, IsOptional, MaxLength } from 'class-validator';

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

  @IsString()
  @MaxLength(100)
  @Column({ type: 'varchar', length: 100 })
  name: string;

  @IsEmail()
  @Column({ type: 'varchar', unique: true })
  email: string;

  @IsOptional()
  @IsString()
  @Column({ type: 'text', nullable: true })
  bio?: string;
}
2

Create a service

Create a service that extends TypeOrmCrudService to handle database operations:
users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService extends TypeOrmCrudService<User> {
  constructor(
    @InjectRepository(User)
    repository: Repository<User>,
  ) {
    super(repository);
  }
}
That’s it! The TypeOrmCrudService provides all CRUD methods out of the box.
3

Create a controller

Create a controller with the @Crud() decorator to automatically generate REST endpoints:
users.controller.ts
import { Controller } from '@nestjs/common';
import { Crud } from '@nestjsx/crud';
import { User } from './user.entity';
import { UsersService } from './users.service';

@Crud({
  model: {
    type: User,
  },
  query: {
    alwaysPaginate: true,
  },
})
@Controller('users')
export class UsersController {
  constructor(public service: UsersService) {}
}
The @Crud() decorator automatically creates these endpoints:
  • GET /users - Get all users
  • GET /users/:id - Get one user
  • POST /users - Create user
  • POST /users/bulk - Create multiple users
  • PATCH /users/:id - Update user
  • PUT /users/:id - Replace user
  • DELETE /users/:id - Delete user
4

Register the module

Register your entities and services in a NestJS module:
users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

Test your API

Start your NestJS application and test the auto-generated endpoints:
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "[email protected]",
    "bio": "Software developer"
  }'

Advanced querying

NestJS CRUD provides powerful query capabilities out of the box. Try these advanced queries:
curl "http://localhost:3000/users?filter=name||eq||John%20Doe"

Filter operators

NestJS CRUD supports a wide range of filter operators:
OperatorDescriptionExample
$eqEquals`filter=nameeqJohn`
$neNot equals`filter=nameneJohn`
$gtGreater than`filter=agegt18`
$ltLess than`filter=agelt65`
$gteGreater than or equal`filter=agegte21`
$lteLess than or equal`filter=agelte100`
$startsStarts with`filter=namestartsJo`
$endsEnds with`filter=emailends.com`
$contContains`filter=namecontoh`
$exclExcludes`filter=nameexcltest`
$inIn array`filter=idin1,2,3`
$notinNot in array`filter=idnotin4,5`
$isnullIs null`filter=bioisnull`
$notnullIs not null`filter=bionotnull`
$betweenBetween values`filter=agebetween18,65`
Add L suffix to any operator for case-insensitive comparisons (e.g., $contL, $startsL, $eqL)

Configure query options

Customize the query behavior in your controller:
users.controller.ts
@Crud({
  model: {
    type: User,
  },
  query: {
    alwaysPaginate: true,
    limit: 20,
    maxLimit: 100,
    sort: [{ field: 'id', order: 'DESC' }],
    join: {
      posts: {
        eager: true,
        alias: 'userPosts',
      },
    },
  },
})
@Controller('users')
export class UsersController {
  constructor(public service: UsersService) {}
}

Override endpoints

You can override any auto-generated endpoint to add custom logic:
users.controller.ts
import { Override, ParsedRequest, CrudRequest } from '@nestjsx/crud';

@Crud({
  model: { type: User },
})
@Controller('users')
export class UsersController {
  constructor(public service: UsersService) {}

  @Override()
  async getOne(@ParsedRequest() req: CrudRequest) {
    console.log('Custom logic before fetching user');
    return this.service.getOne(req);
  }

  @Override('createOneBase')
  async createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: User,
  ) {
    // Add custom validation or business logic
    console.log('Creating user:', dto);
    return this.service.createOne(req, dto);
  }
}

Next steps

Query parameters

Learn about all available query parameters and filtering options

Controllers

Understand CRUD controllers and configuration options

Services

Dive deeper into CRUD services and custom implementations

Advanced features

Explore authentication, serialization, and Swagger integration

Build docs developers (and LLMs) love