DEV Community

Sarwar Hossain
Sarwar Hossain

Posted on

🧭 How to Exclude a Route from Global Prefix & Versioning in NestJS

In NestJS apps, it's common to use global route prefixes and versioning like /api/v1. But sometimes you need a public-facing endpoint β€” such as a payment gateway callback β€” that must live outside those constraints.

Here’s how to expose routes like /payment/callback without the global /api/v1 prefix.

πŸ”§ Problem
You're using global prefixing and versioning like this:

main.ts:

app.setGlobalPrefix('api');
app.enableVersioning({
  type: VersioningType.URI,
  defaultVersion: '1',
});

Enter fullscreen mode Exit fullscreen mode

βœ… Resulting in routes like:

/api/v1/auth/login

/api/v1/user/profile

❌ But now you need /payment/callback to be exposed at:

http://localhost:3000/payment/callback

Instead of:

http://localhost:3000/api/v1/payment/callback

βœ… Solution Overview
You need to do two things:

β›” Exclude the route from the global prefix

β›” Mark the route as version-neutral

  1. Exclude the Route from Global Prefix Update main.ts:
import { RequestMethod } from '@nestjs/common';

app.setGlobalPrefix('api', {
  exclude: [{ path: 'payment/callback', method: RequestMethod.GET }],
});

Enter fullscreen mode Exit fullscreen mode

This tells NestJS to ignore prefixing for GET /payment/callback

🚫 No leading slash in path (correct: payment/callback)

  1. Mark Route as Version-Neutral Update your controller:
import { Controller, Get, Version, VERSION_NEUTRAL } from '@nestjs/common';

@Controller('payment')
export class PaymentController {
  @Get('callback')
  @Version(VERSION_NEUTRAL)
  callback() {
    return 'Payment callback hit!';
  }
}

Enter fullscreen mode Exit fullscreen mode

βœ… VERSION_NEUTRAL tells NestJS: β€œdo not apply any version prefix”

πŸ§ͺ Final Result
http://localhost:3000/payment/callback βœ…

http://localhost:3000/api/v1/payment/callback ❌

All other routes still work normally under /api/v1.

🧡 Conclusion
NestJS makes it easy to maintain clean API versioning β€” but when you need an exception like a public payment callback, it only takes

two steps:

  • Exclude the path in setGlobalPrefix()
  • Add @version(VERSION_NEUTRAL) to the controller

Top comments (0)