Zum Hauptinhalt springen
IT Security NachrichteniPhone Duo zu teuer: Galaxy Z Fold 8 verzeichnet starken Boom(18.09.2026 um 09:38 Uhr)
IT Security DownloadsHyperSnap Download - Umfassendes Screenshot-Tool(18.09.2026 um 09:07 Uhr)
IT Security DownloadsCalibre Download - Kostenloser E-Book-Manager(18.09.2026 um 09:21 Uhr)
IT Security DownloadsMPC-HC Download - Mediaplayer für fast alle Formate(18.09.2026 um 09:32 Uhr)
IT NachrichtenBolt, Lucid plan to deploy 25,000 robotaxis in Europe(18.09.2026 um 09:53 Uhr)
IT NachrichtenFormer Labour deputy leader Tom Watson joins Palantir(18.09.2026 um 08:00 Uhr)
IT Security NachrichteniPhone Duo zu teuer: Galaxy Z Fold 8 verzeichnet starken Boom(18.09.2026 um 09:38 Uhr)
IT Security DownloadsHyperSnap Download - Umfassendes Screenshot-Tool(18.09.2026 um 09:07 Uhr)
IT Security DownloadsCalibre Download - Kostenloser E-Book-Manager(18.09.2026 um 09:21 Uhr)
IT Security DownloadsMPC-HC Download - Mediaplayer für fast alle Formate(18.09.2026 um 09:32 Uhr)
IT NachrichtenBolt, Lucid plan to deploy 25,000 robotaxis in Europe(18.09.2026 um 09:53 Uhr)
IT NachrichtenFormer Labour deputy leader Tom Watson joins Palantir(18.09.2026 um 08:00 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

From Beginner to Pro: Setting Up a TypeScript NestJS Backend with Prisma

From Beginner to Pro: Setting Up a TypeScript NestJS Backend with Prisma

A complete, production-ready guide to building scalable backend applications with NestJS, TypeScript, and Prisma ORM

NestJS TypeScript Prisma PostgreSQL

📋 Table of Contents

  • Why This Stack?
  • Prerequisites
  • Project Structure
  • Quick Start
  • Step-by-Step Setup
  • Database Configuration
  • Building Your First API
  • Authentication & Authorization
  • Testing
  • Deployment
  • Best Practices
  • Troubleshooting
  • Resources

🚀 Why This Stack?

NestJS

  • Enterprise-grade architecture with dependency injection
  • Built on Express/Fastify - familiar, battle-tested foundations
  • TypeScript-first - catch bugs before runtime
  • Microservices ready - scale as you grow
  • Amazing ecosystem - authentication, GraphQL, WebSockets, etc.

Prisma

  • Type-safe database access - autocomplete for your queries
  • Auto-generated migrations - version control your database schema
  • Multi-database support - PostgreSQL, MySQL, MongoDB, SQLite
  • Prisma Studio - visual database browser included
  • Performance - optimized queries out of the box

TypeScript

  • Reduced bugs - 15% fewer bugs in production (Microsoft Research)
  • Better refactoring - rename with confidence
  • Self-documenting code - types as documentation
  • IDE superpowers - IntelliSense everywhere

The result? A backend that's maintainable, scalable, and a joy to develop.

✅ Prerequisites

Before you begin, ensure you have:

  • Node.js (v18+) - Download here
  • npm or yarn - Comes with Node.js
  • PostgreSQL (v12+) - Download here or use Docker
  • Git - Download here
  • Basic knowledge of:
    • JavaScript/TypeScript
    • REST APIs
    • SQL (helpful but not required)

Quick Environment Check

node --version  # Should be v18 or higher
npm --version   # Should be 8 or higher
psql --version  # Should be 12 or higher

📁 Project Structure

nestjs-prisma-backend/
├── prisma/
│   ├── schema.prisma          # Database schema definition
│   ├── migrations/            # Database migration history
│   └── seed.ts               # Seed data for development
├── src/
│   ├── auth/                 # Authentication module
│   │   ├── auth.controller.ts
│   │   ├── auth.service.ts
│   │   ├── auth.module.ts
│   │   ├── dto/              # Data Transfer Objects
│   │   ├── guards/           # Auth guards
│   │   └── strategies/       # Passport strategies
│   ├── users/                # Users module
│   │   ├── users.controller.ts
│   │   ├── users.service.ts
│   │   ├── users.module.ts
│   │   └── dto/
│   ├── posts/                # Posts module (example)
│   │   ├── posts.controller.ts
│   │   ├── posts.service.ts
│   │   ├── posts.module.ts
│   │   └── dto/
│   ├── common/               # Shared utilities
│   │   ├── decorators/       # Custom decorators
│   │   ├── filters/          # Exception filters
│   │   ├── guards/           # Global guards
│   │   ├── interceptors/     # Response interceptors
│   │   └── pipes/            # Validation pipes
│   ├── config/               # Configuration
│   │   ├── database.config.ts
│   │   └── app.config.ts
│   ├── prisma/               # Prisma service
│   │   ├── prisma.service.ts
│   │   └── prisma.module.ts
│   ├── app.module.ts         # Root module
│   ├── app.controller.ts     # Root controller
│   ├── app.service.ts        # Root service
│   └── main.ts              # Application entry point
├── test/                     # E2E tests
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── .env                      # Environment variables
├── .env.example             # Example environment file
├── .eslintrc.js             # ESLint configuration
├── .prettierrc              # Prettier configuration
├── docker-compose.yml       # Docker setup (optional)
├── Dockerfile               # Production Docker image
├── nest-cli.json            # NestJS CLI configuration
├── package.json             # Dependencies
├── tsconfig.json            # TypeScript configuration
└── README.md                # You are here!

⚡ Quick Start

Get up and running in under 5 minutes:

# 1. Clone or create new project
npx @nestjs/cli new nestjs-prisma-backend
cd nestjs-prisma-backend

# 2. Install Prisma
npm install prisma @prisma/client
npm install -D prisma

# 3. Initialize Prisma
npx prisma init

# 4. Set up environment variables
cp .env.example .env
# Edit .env with your database credentials

# 5. Create your schema (see Database Configuration section)

# 6. Run migrations
npx prisma migrate dev --name init

# 7. Generate Prisma Client
npx prisma generate

# 8. Start development server
npm run start:dev

# 🎉 Visit http://localhost:3000

🛠️ Step-by-Step Setup

1. Create NestJS Project

# Install NestJS CLI globally
npm install -g @nestjs/cli

# Create new project
nest new nestjs-prisma-backend

# Choose your package manager (npm/yarn/pnpm)
cd nestjs-prisma-backend

2. Install Dependencies

# Prisma ORM
npm install @prisma/client
npm install -D prisma

# Configuration
npm install @nestjs/config

# Validation
npm install class-validator class-transformer

# Authentication (we'll add this later)
npm install @nestjs/jwt @nestjs/passport passport passport-jwt
npm install -D @types/passport-jwt

# Security
npm install helmet
npm install @nestjs/throttler

# Documentation
npm install @nestjs/swagger swagger-ui-express

3. Initialize Prisma

npx prisma init

This creates:

  • prisma/schema.prisma - Your database schema
  • .env - Environment variables file

4. Configure Environment Variables

Create .env file:

# Database
DATABASE_URL="postgresql://username:password@localhost:5432/nestjs_db?schema=public"

# Application
PORT=3000
NODE_ENV=development

# JWT (for authentication)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=7d

# CORS
CORS_ORIGIN=http://localhost:3000

Create .env.example (commit this to git):

# Database
DATABASE_URL="postgresql://username:password@localhost:5432/database_name?schema=public"

# Application
PORT=3000
NODE_ENV=development

# JWT
JWT_SECRET=change-me-in-production
JWT_EXPIRES_IN=7d

# CORS
CORS_ORIGIN=http://localhost:3000

🗄️ Database Configuration

Step 1: Define Your Schema

Edit prisma/schema.prisma:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String?
  password  String
  role      Role     @default(USER)
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@map("users")
}

model Post {
  id          String   @id @default(uuid())
  title       String
  content     String?
  published   Boolean  @default(false)
  author      User     @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId    String
  tags        Tag[]
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@map("posts")
  @@index([authorId])
}

model Tag {
  id    String @id @default(uuid())
  name  String @unique
  posts Post[]

  @@map("tags")
}

enum Role {
  USER
  ADMIN
  MODERATOR
}

Step 2: Create Migration

npx prisma migrate dev --name init

This will:

  • Create the database if it doesn't exist
  • Generate SQL migration files
  • Apply migrations to your database
  • Generate Prisma Client

Step 3: Create Prisma Service

Create src/prisma/prisma.service.ts:

import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
  async onModuleInit() {
    await this.$connect();
    console.log('✅ Database connected');
  }

  async onModuleDestroy() {
    await this.$disconnect();
    console.log('❌ Database disconnected');
  }

  // Helper method for transactions
  async executeTransaction<T>(fn: (prisma: PrismaClient) => Promise<T>): Promise<T> {
    return this.$transaction(fn);
  }
}

Create src/prisma/prisma.module.ts:

import { Module, Global } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class PrismaModule {}

Step 4: Register Prisma Module

Update src/app.module.ts:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PrismaModule } from './prisma/prisma.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    PrismaModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

🏗️ Building Your First API

Step 1: Generate Resource

nest generate resource users

Choose:

  • Transport layer: REST API
  • Generate CRUD entry points: Yes

Step 2: Create DTOs

Create src/users/dto/create-user.dto.ts:

import { IsEmail, IsNotEmpty, IsString, MinLength, IsOptional, IsEnum } from 'class-validator';
import { Role } from '@prisma/client';

export class CreateUserDto {
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  name: string;

  @IsString()
  @MinLength(8, { message: 'Password must be at least 8 characters long' })
  password: string;

  @IsOptional()
  @IsEnum(Role)
  role?: Role;
}

Create src/users/dto/update-user.dto.ts:

import { PartialType } from '@nestjs/mapped-types';
import { CreateUserDto } from './create-user.dto';
import { IsOptional, IsString } from 'class-validator';

export class UpdateUserDto extends PartialType(CreateUserDto) {
  @IsOptional()
  @IsString()
  name?: string;
}

Step 3: Implement Service

Update src/users/users.service.ts:

import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import * as bcrypt from 'bcrypt';

@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  async create(createUserDto: CreateUserDto) {
    // Check if user already exists
    const existingUser = await this.prisma.user.findUnique({
      where: { email: createUserDto.email },
    });

    if (existingUser) {
      throw new ConflictException('User with this email already exists');
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(createUserDto.password, 10);

    // Create user
    const user = await this.prisma.user.create({
      data: {
        ...createUserDto,
        password: hashedPassword,
      },
      select: {
        id: true,
        email: true,
        name: true,
        role: true,
        createdAt: true,
        updatedAt: true,
      },
    });

    return user;
  }

  async findAll() {
    return this.prisma.user.findMany({
      select: {
        id: true,
        email: true,
        name: true,
        role: true,
        createdAt: true,
        updatedAt: true,
      },
    });
  }

  async findOne(id: string) {
    const user = await this.prisma.user.findUnique({
      where: { id },
      select: {
        id: true,
        email: true,
        name: true,
        role: true,
        posts: {
          select: {
            id: true,
            title: true,
            published: true,
            createdAt: true,
          },
        },
        createdAt: true,
        updatedAt: true,
      },
    });

    if (!user) {
      throw new NotFoundException(`User with ID ${id} not found`);
    }

    return user;
  }

  async findByEmail(email: string) {
    return this.prisma.user.findUnique({
      where: { email },
    });
  }

  async update(id: string, updateUserDto: UpdateUserDto) {
    // Check if user exists
    await this.findOne(id);

    // If password is being updated, hash it
    if (updateUserDto.password) {
      updateUserDto.password = await bcrypt.hash(updateUserDto.password, 10);
    }

    const user = await this.prisma.user.update({
      where: { id },
      data: updateUserDto,
      select: {
        id: true,
        email: true,
        name: true,
        role: true,
        createdAt: true,
        updatedAt: true,
      },
    });

    return user;
  }

  async remove(id: string) {
    // Check if user exists
    await this.findOne(id);

    await this.prisma.user.delete({
      where: { id },
    });

    return { message: 'User deleted successfully' };
  }
}

Install bcrypt:

npm install bcrypt
npm install -D @types/bcrypt

Step 4: Update Controller

Update src/users/users.controller.ts:

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  HttpCode,
  HttpStatus,
  UseGuards,
} from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  @HttpCode(HttpStatus.CREATED)
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(id, updateUserDto);
  }

  @Delete(':id')
  @HttpCode(HttpStatus.NO_CONTENT)
  remove(@Param('id') id: string) {
    return this.usersService.remove(id);
  }
}

Step 5: Enable Validation

Update src/main.ts:

import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
import * as helmet from 'helmet';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Global validation pipe
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true, // Strip properties that don't have decorators
      forbidNonWhitelisted: true, // Throw error if non-whitelisted properties exist
      transform: true, // Auto-transform payloads to DTO instances
    }),
  );

  // Security
  app.use(helmet());

  // CORS
  app.enableCors({
    origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
    credentials: true,
  });

  // Global prefix
  app.setGlobalPrefix('api/v1');

  const port = process.env.PORT || 3000;
  await app.listen(port);

  console.log(`🚀 Application is running on: http://localhost:${port}`);
}
bootstrap();

Step 6: Test Your API

# Start the server
npm run start:dev

# Create a user (using curl or Postman)
curl -X POST http://localhost:3000/api/v1/users \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "name": "John Doe",
    "password": "securepassword123"
  }'

# Get all users
curl http://localhost:3000/api/v1/users

# Get specific user
curl http://localhost:3000/api/v1/users/{user-id}

🔐 Authentication & Authorization

Step 1: Generate Auth Module

nest generate module auth
nest generate service auth
nest generate controller auth

Step 2: Create Auth DTOs

Create src/auth/dto/login.dto.ts:

import { IsEmail, IsNotEmpty, IsString } from 'class-validator';

export class LoginDto {
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  password: string;
}

Create src/auth/dto/register.dto.ts:

import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';

export class RegisterDto {
  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  name: string;

  @IsString()
  @MinLength(8)
  password: string;
}

Step 3: Implement Auth Service

Update src/auth/auth.service.ts:

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../prisma/prisma.service';
import { UsersService } from '../users/users.service';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  constructor(
    private prisma: PrismaService,
    private jwtService: JwtService,
    private usersService: UsersService,
  ) {}

  async register(registerDto: RegisterDto) {
    const user = await this.usersService.create(registerDto);
    const token = this.generateToken(user.id, user.email);

    return {
      user,
      access_token: token,
    };
  }

  async login(loginDto: LoginDto) {
    const user = await this.usersService.findByEmail(loginDto.email);

    if (!user) {
      throw new UnauthorizedException('Invalid credentials');
    }

    const isPasswordValid = await bcrypt.compare(loginDto.password, user.password);

    if (!isPasswordValid) {
      throw new UnauthorizedException('Invalid credentials');
    }

    const token = this.generateToken(user.id, user.email);

    return {
      user: {
        id: user.id,
        email: user.email,
        name: user.name,
        role: user.role,
      },
      access_token: token,
    };
  }

  async validateUser(userId: string) {
    return this.usersService.findOne(userId);
  }

  private generateToken(userId: string, email: string): string {
    const payload = { sub: userId, email };
    return this.jwtService.sign(payload);
  }
}

Step 4: Create JWT Strategy

Create src/auth/strategies/jwt.strategy.ts:

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from '../auth.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: process.env.JWT_SECRET,
    });
  }

  async validate(payload: any) {
    const user = await this.authService.validateUser(payload.sub);

    if (!user) {
      throw new UnauthorizedException();
    }

    return user;
  }
}

Step 5: Create JWT Guard

Create src/auth/guards/jwt-auth.guard.ts:

import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

Step 6: Create Custom Decorator

Create src/common/decorators/current-user.decorator.ts:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const CurrentUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);

Step 7: Update Auth Module

Update src/auth/auth.module.ts:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './strategies/jwt.strategy';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [
    UsersModule,
    PassportModule,
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: { expiresIn: process.env.JWT_EXPIRES_IN || '7d' },
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  exports: [AuthService],
})
export class AuthModule {}

Step 8: Update Auth Controller

Update src/auth/auth.controller.ts:

import { Controller, Post, Body, HttpCode, HttpStatus, Get, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
import { JwtAuthGuard } from './guards/jwt-auth.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('register')
  @HttpCode(HttpStatus.CREATED)
  register(@Body() registerDto: RegisterDto) {
    return this.authService.register(registerDto);
  }

  @Post('login')
  @HttpCode(HttpStatus.OK)
  login(@Body() loginDto: LoginDto) {
    return this.authService.login(loginDto);
  }

  @Get('me')
  @UseGuards(JwtAuthGuard)
  getProfile(@CurrentUser() user: any) {
    return user;
  }
}

Step 9: Protect Routes

Update src/users/users.controller.ts to add authentication:

import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';

@Controller('users')
@UseGuards(JwtAuthGuard) // Protect all routes
export class UsersController {
  // ... existing code

  @Get('profile')
  getProfile(@CurrentUser() user: any) {
    return user;
  }
}

Step 10: Test Authentication

# Register a new user
curl -X POST http://localhost:3000/api/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "name": "Test User",
    "password": "password123"
  }'

# Login
curl -X POST http://localhost:3000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "password123"
  }'

# Use the returned token to access protected routes
curl http://localhost:3000/api/v1/auth/me \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

🧪 Testing

Unit Tests

Create src/users/users.service.spec.ts:

import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { PrismaService } from '../prisma/prisma.service';

describe('UsersService', () => {
  let service: UsersService;
  let prisma: PrismaService;

  const mockPrismaService = {
    user: {
      create: jest.fn(),
      findMany: jest.fn(),
      findUnique: jest.fn(),
      update: jest.fn(),
      delete: jest.fn(),
    },
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        {
          provide: PrismaService,
          useValue: mockPrismaService,
        },
      ],
    }).compile();

    service = module.get<UsersService>(UsersService);
    prisma = module.get<PrismaService>(PrismaService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('findAll', () => {
    it('should return an array of users', async () => {
      const mockUsers = [
        { id: '1', email: '[email protected]', name: 'Test User' },
      ];

      mockPrismaService.user.findMany.mockResolvedValue(mockUsers);

      const result = await service.findAll();
      expect(result).toEqual(mockUsers);
      expect(prisma.user.findMany).toHaveBeenCalled();
    });
  });
});

Run tests:

npm run test          # Unit tests
npm run test:watch    # Watch mode
npm run test:cov      # Coverage report

E2E Tests

Create test/users.e2e-spec.ts:

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('Users (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    app.useGlobalPipes(new ValidationPipe());
    await app.init();
  });

  afterAll(async () => {
    await app.close();
  });

  it('/api/v1/users (POST)', () => {
    return request(app.getHttpServer())
      .post('/api/v1/users')
      .send({
        email: '[email protected]',
        name: 'Test User',
        password: 'password123',
      })
      .expect(201)
      .expect((res) => {
        expect(res.body).toHaveProperty('id');
        expect(res.body.email).toBe('[email protected]');
      });
  });

  it('/api/v1/users (GET)', () => {
    return request(app.getHttpServer())
      .get('/api/v1/users')
      .expect(200)
      .expect((res) => {
        expect(Array.isArray(res.body)).toBe(true);
      });
  });
});

Run e2e tests:

npm run test:e2e

🚢 Deployment

Docker Setup

Create Dockerfile:

# Build stage
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm ci

COPY . .

RUN npm run build

# Production stage
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
COPY prisma ./prisma/

RUN npm ci --only=production

COPY --from=builder /app/dist ./dist

EXPOSE 3000

CMD ["sh", "-c", "npx prisma migrate deploy && node dist/main"]

Create docker-compose.yml:

version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: nestjs_db
    ports:
      - '5432:5432'
    volumes:
      - postgres_data:/var/lib/postgresql/data

  app:
    build: .
    ports:
      - '3000:3000'
    environment:
      DATABASE_URL: postgresql://postgres:postgres@postgres:5432/nestjs_db?schema=public
      JWT_SECRET: your-production-secret-change-this
      NODE_ENV: production
    depends_on:
      - postgres

volumes:
  postgres_data:

Run with Docker:

docker-compose up -d

Deployment Checklist

  • [ ] Set strong JWT_SECRET in production
  • [ ] Use environment-specific .env files
  • [ ] Enable HTTPS/SSL
  • [ ] Set up proper CORS origins
  • [ ] Enable rate limiting
  • [ ] Set up logging (Winston, Pino)
  • [ ] Add health check endpoint
  • [ ] Set up monitoring (Sentry, DataDog)
  • [ ] Configure reverse proxy (Nginx, Caddy)
  • [ ] Set up CI/CD pipeline
  • [ ] Database backups configured
  • [ ] Review Prisma connection pooling

💎 Best Practices

1. Error Handling

Create src/common/filters/http-exception.filter.ts:

import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const message =
      exception instanceof HttpException
        ? exception.getResponse()
        : 'Internal server error';

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message,
    });
  }
}

2. Logging

Create src/common/interceptors/logging.interceptor.ts:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  private readonly logger = new Logger(LoggingInterceptor.name);

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const { method, url } = request;
    const now = Date.now();

    return next.handle().pipe(
      tap(() => {
        const response = context.switchToHttp().getResponse();
        const { statusCode } = response;
        const delay = Date.now() - now;

        this.logger.log(`${method} ${url} ${statusCode} - ${delay}ms`);
      }),
    );
  }
}

3. API Documentation with Swagger

Update src/main.ts:

import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Swagger configuration
  const config = new DocumentBuilder()
    .setTitle('NestJS Prisma API')
    .setDescription('API documentation for NestJS + Prisma backend')
    .setVersion('1.0')
    .addBearerAuth()
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api/docs', app, document);

  await app.listen(3000);
  console.log(`📚 API Documentation: http://localhost:3000/api/docs`);
}

4. Rate Limiting

Install throttler:

npm install @nestjs/throttler

Update app.module.ts:

import { ThrottlerModule } from '@nestjs/throttler';

@Module({
  imports: [
    ThrottlerModule.forRoot([{
      ttl: 60000, // 1 minute
      limit: 10,  // 10 requests per minute
    }]),
    // ... other imports
  ],
})
export class AppModule {}

5. Database Seeding

Create prisma/seed.ts:

import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcrypt';

const prisma = new PrismaClient();

async function main() {
  // Create admin user
  const hashedPassword = await bcrypt.hash('admin123', 10);

  const admin = await prisma.user.upsert({
    where: { email: '[email protected]' },
    update: {},
    create: {
      email: '[email protected]',
      name: 'Admin User',
      password: hashedPassword,
      role: 'ADMIN',
    },
  });

  console.log('✅ Seed data created:', { admin });
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

Add to package.json:

{
  "prisma": {
    "seed": "ts-node prisma/seed.ts"
  }
}

Run seed:

npx prisma db seed

🐛 Troubleshooting

Common Issues

1. Prisma Client Not Generated

# Generate Prisma Client
npx prisma generate

2. Migration Failed

# Reset database (WARNING: deletes all data)
npx prisma migrate reset

# Or create a new migration
npx prisma migrate dev --name fix_migration

3. TypeScript Errors

# Clear cache and rebuild
rm -rf dist node_modules package-lock.json
npm install
npm run build

4. Database Connection Issues

Check your .env file:

# Correct format
DATABASE_URL="postgresql://username:password@localhost:5432/database_name"

# Common mistakes:
# ❌ Missing quotes
# ❌ Wrong port
# ❌ Incorrect schema name

5. JWT Authentication Not Working

  • Verify JWT_SECRET is set in .env
  • Check token format: Bearer <token>
  • Ensure JwtAuthGuard is applied correctly
  • Verify user exists in database

📚 Resources

Official Documentation

Learning Resources

Tools

Community

👨‍💻 Author

Rajat

⭐ Support

If this guide helped you, please consider:

  • Sharing it with other developers
  • Following for more content

Happy Coding! 🚀

Made with ❤️ by Rajat

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten From Beginner to Pro: Setting Up a TypeScript NestJS Backend with Prisma

Thematisch verwandte Begriffe: From, Beginner, Setting, TypeScript · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61591 | djust provides Phoenix LiveView-style reactive server-side rendering for…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
News ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

↗ Original-Quelle