@mgvdev/nestjs-bun-adapter
v0.1.0
Published
Bun HTTP adapter for NestJS
Readme
@mgvdev/nestjs-bun-adapter
A lightweight NestJS HTTP adapter powered by Bun.
It replaces the default Express/Fastify adapter by Bun.serve() and provides native WebSocket support, file uploads, streaming, sessions, rate limiting and compression — all without leaving the Bun runtime.
Requirements
- Bun >= 1.2.0
- @nestjs/common >= 11.0.0
- @nestjs/core >= 11.0.0
Installation
bun add @mgvdev/nestjs-bun-adapterPeer dependencies (NestJS core packages) must be installed in your project.
Basic usage
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { BunHttpAdapter } from '@mgvdev/nestjs-bun-adapter';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, new BunHttpAdapter());
await app.listen(3000);
}
bootstrap();Start the application with Bun:
bun run src/main.tsAdapter options
const adapter = new BunHttpAdapter({
maxBodySize: 1024 * 1024, // 1 MB body limit
gracefulShutdown: true, // wait for active connections on close()
});maxBodySize: maximum body size in bytes (returns413 Payload Too Largewhen exceeded)gracefulShutdown: whentrue,app.close()stops accepting new connections and waits for active ones to close. Defaults tofalsefor tests and short-lived processes.
WebSockets
Use BunWsAdapter together with @nestjs/websockets:
import { NestFactory } from '@nestjs/core';
import { BunHttpAdapter, BunWsAdapter } from '@mgvdev/nestjs-bun-adapter';
async function bootstrap() {
const adapter = new BunHttpAdapter();
const app = await NestFactory.create(AppModule, adapter);
const wsAdapter = new BunWsAdapter(app);
wsAdapter.setHttpAdapter(adapter);
app.useWebSocketAdapter(wsAdapter);
await app.listen(3000);
}
bootstrap();CORS
Enable CORS the standard NestJS way:
app.enableCors({
origin: 'http://localhost:3001',
credentials: true,
});Static assets
app.useStaticAssets(join(__dirname, '..', 'public'), { prefix: '/public' });File upload
Use the built-in interceptors with multipart forms:
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('upload')
export class UploadController {
@Post()
@UseInterceptors(FileInterceptor('file'))
upload(@UploadedFile() file: Express.Multer.File) {
return { filename: file.originalname, size: file.size };
}
}Sessions
import { sessionMiddleware, MemorySessionStore } from '@mgvdev/nestjs-bun-adapter';
app.use(sessionMiddleware({
secret: 'change-me-in-production',
name: 'myapp.sid',
cookie: { httpOnly: true, maxAge: 24 * 60 * 60 * 1000 },
store: new MemorySessionStore(),
}));Access the session in controllers via req.session:
@Get('profile')
profile(@Req() req: Request & { session: any }) {
req.session.data.visits = (req.session.data.visits || 0) + 1;
return { visits: req.session.data.visits };
}Rate limiting
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { RateLimiterInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('api')
export class ApiController {
@Get()
@UseInterceptors(RateLimiterInterceptor({ windowMs: 60000, max: 10 }))
findAll() {
return { ok: true };
}
}A RateLimiterGuard is also available.
Response compression
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { CompressionInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('data')
export class DataController {
@Get()
@UseInterceptors(CompressionInterceptor({ threshold: 1024, level: 6 }))
getLargePayload() {
return 'a'.repeat(5000);
}
}Supported encodings: br (brotli), gzip and deflate. The interceptor picks the best encoding based on the Accept-Encoding header and quality values.
Swagger / OpenAPI
@nestjs/swagger works out of the box to generate an OpenAPI document:
bun add @nestjs/swaggerimport { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
const config = new DocumentBuilder().setTitle('My API').setVersion('1.0').build();
const document = SwaggerModule.createDocument(app, config);
// Serve the JSON spec from a controller or expose it directly:
app.use('/api-json', (req, res) => res.json(document));Note: SwaggerModule.setup() is not supported because it relies on Express/Fastify middleware. You can serve the generated document through a standard NestJS controller instead.
Streaming
Stream a file with NestJS StreamableFile:
import { Controller, Get, StreamableFile } from '@nestjs/common';
import { createReadStream } from 'fs';
@Controller('stream')
export class StreamController {
@Get('file')
getFile(): StreamableFile {
const stream = createReadStream('./big-file.bin');
return new StreamableFile(stream);
}
}Server-Sent Events are supported by returning an Observable:
import { Controller, Get, Sse } from '@nestjs/common';
import { interval, map } from 'rxjs';
@Controller('sse')
export class SseController {
@Sse('events')
events() {
return interval(1000).pipe(map((count) => ({ data: { count } })));
}
}View engine
app.setViewEngine('ejs');
app.setBaseViewsDir(join(__dirname, '..', 'views'));@Get('hello')
@Render('hello')
getHello() {
return { name: 'World' };
}Middlewares intégrés
Request logger
import { RequestLoggerInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('api')
@UseInterceptors(RequestLoggerInterceptor())
export class ApiController {}Format personnalisable :
RequestLoggerInterceptor({
format: (info) => `${info.method} ${info.url} ${info.statusCode} - ${info.duration}ms`,
})Security headers
import { SecurityHeadersInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('api')
@UseInterceptors(SecurityHeadersInterceptor())
export class ApiController {}Headers configurables : X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Strict-Transport-Security, Referrer-Policy, Content-Security-Policy.
Timeout
import { TimeoutInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('api')
@UseInterceptors(TimeoutInterceptor({ ms: 5000 }))
export class ApiController {}Request ID
import { requestIdMiddleware, RequestIdInterceptor } from '@mgvdev/nestjs-bun-adapter';
app.use(requestIdMiddleware());Le middleware génère un x-request-id s'il n'est pas fourni et l'expose dans req.requestId. L'intercepteur RequestIdInterceptor peut être utilisé pour répercuter l'ID dans la réponse.
Cache mémoire
import { CacheInterceptor } from '@mgvdev/nestjs-bun-adapter';
@Controller('api')
@UseInterceptors(CacheInterceptor({ ttl: 60000 }))
export class ApiController {}Graceful shutdown
const app = await NestFactory.create(AppModule, new BunHttpAdapter());
app.enableShutdownHooks();
await app.listen(3000);Compatibility
| Feature | Status | | ---------------------- | ------ | | Controllers & routing | ✅ | | Middleware | ✅ | | Guards | ✅ | | Interceptors | ✅ | | Pipes | ✅ | | Exception filters | ✅ | | URI versioning | ✅ | | CORS | ✅ | | Static assets | ✅ | | View engine | ✅ | | Multipart upload | ✅ | | Streaming | ✅ | | WebSockets | ✅ | | Swagger / OpenAPI | ✅ | | HTTP/2 | ✅ | | Request logger | ✅ | | Security headers | ✅ | | Timeout interceptor | ✅ | | Request ID | ✅ | | Cache interceptor | ✅ |
License
MIT
