VelaVela
Fundamentals

Middleware

Middleware runs before route handlers, with access to the request context.

Middleware functions execute before route handlers and have full access to the request context. They can modify the request, short-circuit the response, or pass control to the next handler.

NestMiddleware Interface

Middleware classes implement the NestMiddleware interface:

import { Injectable, NestMiddleware } from '@velajs/vela';
import type { Context, Next } from 'hono';

@Injectable()
class LoggingMiddleware implements NestMiddleware {
  async use(c: Context, next: Next): Promise<Response | void> {
    const start = Date.now();
    console.log(`--> ${c.req.method} ${c.req.path}`);

    await next();

    const ms = Date.now() - start;
    console.log(`<-- ${c.req.method} ${c.req.path} ${ms}ms`);
  }
}

Middleware receives Hono's Context object, giving you access to the full request and response API.

Applying Middleware

Decorator-based

Use @UseMiddleware() at the class or method level:

import { Controller, Get, UseMiddleware } from '@velajs/vela';

@Controller('spirits')
@UseMiddleware(LoggingMiddleware)
class SpiritsController {
  @Get()
  findAll() {
    return [];
  }

  @Get(':id')
  @UseMiddleware(AnotherMiddleware)
  findOne(@Param('id') id: string) {
    return { id };
  }
}

When applied at the class level, the middleware runs for all routes in the controller. When applied at the method level, it runs only for that route.

Global Middleware

Register middleware that runs for every request using useGlobalMiddleware():

const app = await VelaFactory.create(AppModule);

app.useGlobalMiddleware(LoggingMiddleware);

Provider-based

Use the APP_MIDDLEWARE injection token to register global middleware through the module system:

import { Module, APP_MIDDLEWARE } from '@velajs/vela';

@Module({
  providers: [
    LoggingMiddleware,
    {
      provide: APP_MIDDLEWARE,
      useExisting: LoggingMiddleware,
    },
  ],
})
class AppModule {}

This approach lets your middleware participate in dependency injection, so it can inject other providers.

Class vs Instance Middleware

Middleware can be a class or an instance:

  • Class middleware — decorated with @Injectable(), resolved through DI, can inject other providers
  • Instance middleware — a plain object with a use method, does not participate in DI
// Class middleware (recommended)
@Injectable()
class AuthMiddleware implements NestMiddleware {
  constructor(private authService: AuthService) {}

  async use(c: Context, next: Next) {
    const token = c.req.header('authorization');
    if (!this.authService.verify(token)) {
      return c.json({ error: 'Unauthorized' }, 401);
    }
    await next();
  }
}

Example: CORS Middleware

@Injectable()
class CorsMiddleware implements NestMiddleware {
  async use(c: Context, next: Next) {
    c.header('Access-Control-Allow-Origin', '*');
    c.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
    c.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

    if (c.req.method === 'OPTIONS') {
      return c.text('', 204);
    }

    await next();
  }
}
Edit on GitHub

Last updated on

On this page