5 min readUpdated May 24, 2025

Enabling CORS in NestJS for Production: A Secure and Practical Guide

Deploying a NestJS API to production often triggers CORS errors—like “No ‘Access-Control-Allow-Origin’ header is present”—when your frontend or third-party clients live on a different domain. Using app.enableCors() with a secure configuration—restricting origins via an environment-driven whitelist, specifying allowed methods, and enabling credentials only when needed—ensures your API remains both accessible and protected.

Written by

TypeScriptNestJSReact, Vue and Typescript

Enabling CORS in NestJS for Production: A Secure and Practical Guide

When deploying a NestJS API to production, you might encounter browser errors like No 'Access-Control-Allow-Origin' header is present if Cross-Origin Resource Sharing (CORS) isn’t properly configured. This is a common challenge when your API serves a frontend on a different domain or external clients. In this post, we’ll explore how to enable and configure CORS in NestJS for production, ensuring your API is secure and accessible.

What Is CORS and Why Does It Matter?

CORS is a browser security feature that controls whether a web page from one origin (e.g., www.example.com) can make requests to a different origin (e.g., api.example.com). Without proper CORS configuration, browsers block these requests to protect users from unauthorized access. In a NestJS application, enabling CORS is essential when:

  • Your frontend and backend are hosted on different domains.
  • External clients or third-party apps consume your API.
  • You’re using authentication with cookies or tokens, requiring credential support.

In development, you might use permissive CORS settings, but production demands a secure, specific configuration to prevent unauthorized access.

The Challenge: Enabling CORS in Production

Developers often face issues with CORS in production due to:

  • Overly permissive settings: Allowing all origins (*) is insecure.
  • Missing credentials support: Needed for cookies or authentication headers.
  • Reverse proxy interference: Tools like Nginx may strip or modify CORS headers.
  • Dynamic origins: Production may require multiple allowed origins based on environment.

NestJS provides a simple enableCors() method, but production requires careful configuration. Let’s see how to set it up correctly.

Solution: Enabling CORS in NestJS

NestJS offers built-in CORS support via app.enableCors(). For production, you can customize it to allow specific origins, methods, and credentials. Here’s a step-by-step guide.

Step 1: Basic CORS Setup

In src/main.ts, enable CORS with default settings:

1import { NestFactory } from '@nestjs/core'; 2import { AppModule } from './app.module'; 3 4async function bootstrap() { 5 const app = await NestFactory.create(AppModule); 6 app.enableCors(); // Enables CORS for all origins 7 await app.listen(3000); 8} 9bootstrap();

This allows all origins (*), all methods (GET, POST, etc.), and no credentials—suitable for development but insecure for production.

Step 2: Configure CORS for Production

For a secure setup, specify allowed origins, methods, and credentials using environment variables for flexibility.

Install @nestjs/config for environment variable support:

1npm install @nestjs/config

Create a .env file in your project root:

1ALLOWED_ORIGINS=https://www.example.com,https://app.example.com 2PORT=3000

Update src/main.ts to use dynamic CORS configuration:

1import { NestFactory } from '@nestjs/core'; 2import { AppModule } from './app.module'; 3import { ConfigService } from '@nestjs/config'; 4 5async function bootstrap() { 6 const app = await NestFactory.create(AppModule); 7 const configService = app.get(ConfigService); 8 const allowedOrigins = configService.get<string>('ALLOWED_ORIGINS')?.split(',') || []; 9 10 app.enableCors({ 11 origin: (origin, callback) => { 12 if (!origin || allowedOrigins.includes(origin)) { 13 callback(null, true); 14 } else { 15 callback(new Error('Not allowed by CORS')); 16 } 17 }, 18 methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], 19 credentials: true, // Allow cookies and auth headers 20 }); 21 22 const port = configService.get<number>('PORT') || 3000; 23 await app.listen(port); 24} 25bootstrap();

Update src/app.module.ts to include ConfigModule:

1import { Module } from '@nestjs/common'; 2import { ConfigModule } from '@nestjs/config'; 3 4@Module({ 5 imports: [ 6 ConfigModule.forRoot({ 7 isGlobal: true, 8 envFilePath: '.env', 9 }), 10 ], 11}) 12export class AppModule {}

This setup:

  • Allows only origins listed in ALLOWED_ORIGINS.
  • Supports credentials for authenticated requests.
  • Restricts HTTP methods for security.
  • Uses ConfigService for environment variable management.

Step 3: Create a Sample Endpoint

To test CORS, create a UsersModule. In src/users/users.controller.ts:

1import { Controller, Get } from '@nestjs/common'; 2 3@Controller('users') 4export class UsersController { 5 @Get() 6 getUsers() { 7 return [{ id: 1, name: 'John Doe' }]; 8 } 9}

In src/users/users.module.ts:

1import { Module } from '@nestjs/common'; 2import { UsersController } from './users.controller'; 3 4@Module({ 5 controllers: [UsersController], 6}) 7export class UsersModule {}

Update src/app.module.ts:

1import { Module } from '@nestjs/common'; 2import { ConfigModule } from '@nestjs/config'; 3import { UsersModule } from './users/users.module'; 4 5@Module({ 6 imports: [ 7 ConfigModule.forRoot({ 8 isGlobal: true, 9 envFilePath: '.env', 10 }), 11 UsersModule, 12 ], 13}) 14export class AppModule {}

Step 4: Test CORS in Production

Deploy your app to a production-like environment (e.g., using Docker or a hosting service). Test from a frontend on https://www.example.com:

  • Request: GET https://api.example.com/users with Origin: https://www.example.com.
  • Response: Should include Access-Control-Allow-Origin: https://www.example.com and the user data.
  • Invalid Origin: Requests from https://unauthorized.com should fail with a CORS error.

For local testing, use a browser or a tool like Postman, but ensure production tests use real browser requests to verify CORS behavior.

Step 5: Handle Reverse Proxies (Optional)

In production, a reverse proxy like Nginx may interfere with CORS headers. Configure Nginx to preserve them:

1server { 2 listen 80; 3 server_name api.example.com; 4 5 location / { 6 proxy_pass http://localhost:3000; 7 proxy_set_header Host $host; 8 proxy_set_header X-Real-IP $remote_addr; 9 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 10 add_header Access-Control-Allow-Origin $http_origin; 11 add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH"; 12 add_header Access-Control-Allow-Credentials true; 13 } 14}

This ensures Nginx forwards CORS headers correctly.

Best Practices for CORS in Production

  • Restrict Origins: Allow only trusted domains (e.g., https://www.example.com) instead of *.
  • Use Environment Variables: Store allowed origins in .env files for flexibility across environments.
  • Enable Credentials Carefully: Set credentials: true only for cookies or auth headers, with strict origin control.
  • Handle Preflight Requests: Support OPTIONS requests for complex methods or headers.
  • Test in Production: Verify CORS with real browser requests, not just development tools.
  • Monitor Proxy Configurations: Ensure proxies like Nginx or Cloudflare preserve CORS headers.

Common Pitfalls

  • Allowing All Origins (*): Insecure in production, especially with credentials.
  • Missing Credentials Support: Forgetting credentials: true for authenticated requests.
  • Proxy Misconfiguration: Reverse proxies stripping CORS headers.
  • Dynamic Origin Issues: Not handling undefined origin headers from non-browser clients.

Conclusion

Enabling CORS in a NestJS application for production is straightforward with app.enableCors(), but a secure setup requires specifying allowed origins, methods, and credentials. Using @nestjs/config for dynamic origins and testing thoroughly ensures your API is accessible and secure. Whether serving a frontend or external clients, proper CORS configuration is essential for a production-ready NestJS app.

Have you faced CORS challenges in your NestJS projects? Share your tips or questions in the comments below!

Happy coding, and keep building secure NestJS APIs!

About

Software Developer & Consultant specializing in JavaScript, TypeScript, and modern web technologies.

Share this article