elysia-nestjs
v0.0.2
Published
NestJS HTTP adapter powered by Elysia
Readme
elysia-nestjs
elysia-nestjs is a NestJS 11 HTTP adapter backed by Elysia. It supports Bun natively and Node.js through Elysia's official Node adapter.
The package has three intentional entry points:
| Import | Provides |
| --- | --- |
| elysia-nestjs | HTTP adapter and public request/reply types |
| elysia-nestjs/graphql | Apollo GraphQL HTTP driver and graphql-ws subscriptions |
| elysia-nestjs/uploads | Optional REST multipart helpers and GraphQL Upload scalar |
Requirements
- NestJS 11 (
@nestjs/commonand@nestjs/core) - Bun, or Node.js with
@elysia/node reflect-metadataandrxjsin the Nest application
GraphQL is opt-in and requires @nestjs/graphql, @nestjs/apollo, @apollo/server, and graphql. The complete, current list of Elysia constructor options is maintained in the Elysia documentation; this adapter forwards those options unchanged.
Installation
bun add elysia-nestjs elysia @nestjs/common @nestjs/core reflect-metadata rxjsFor Node.js, add the official adapter:
bun add @elysia/nodeFor GraphQL:
bun add @nestjs/graphql @nestjs/apollo @apollo/server graphqlFor subscriptions, add the protocol implementation:
bun add graphql-wsUploads are included only when importing elysia-nestjs/uploads; no extra package is needed.
Quick start
Bun
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { ElysiaAdapter } from 'elysia-nestjs';
import { AppModule } from './app.module';
const app = await NestFactory.create(AppModule, new ElysiaAdapter());
await app.listen(3000);Node.js
import 'reflect-metadata';
import { node } from '@elysia/node';
import { NestFactory } from '@nestjs/core';
import { ElysiaAdapter } from 'elysia-nestjs';
import { AppModule } from './app.module';
const app = await NestFactory.create(
AppModule,
new ElysiaAdapter({ adapter: node() }),
);
await app.listen(3000);HTTP adapter
Nest controllers, middleware, guards, interceptors, filters, versioning, and StreamableFile responses are dispatched through the adapter. The request object exposed to Nest is a Fetch-style ElysiaRequest; its original Request is available as req.raw.
import { Body, Controller, Get, Param, Post, Req } from '@nestjs/common';
import type { ElysiaRequest } from 'elysia-nestjs';
@Controller('users')
export class UsersController {
@Get(':id')
findOne(@Param('id') id: string, @Req() req: ElysiaRequest) {
return { id, query: req.query };
}
@Post()
create(@Body() body: unknown) {
return body;
}
}Pass any Elysia constructor option directly to ElysiaAdapter:
const adapter = new ElysiaAdapter({
name: 'api',
strictPath: true,
aot: true,
serve: { maxRequestBodySize: 10 * 1024 * 1024 },
});Body parsers and raw bodies
Nest registers JSON, text, and URL-encoded parsers during application initialization. To capture the original bytes or set a per-parser limit, configure the adapter before bootstrapping:
const adapter = new ElysiaAdapter();
adapter.useBodyParser('application/json', true, 1024 * 1024);
const app = await NestFactory.create(AppModule, adapter);req.rawBody is a Buffer when raw capture is enabled. Invalid JSON produces a Nest 400 error; bodies over the configured limit produce 413.
CORS
enableCors installs the official @elysiajs/cors plugin. Use that plugin's option names:
app.enableCors({
origin: ['https://app.example.com'],
methods: ['GET', 'POST', 'PATCH', 'DELETE'],
allowedHeaders: ['content-type', 'authorization'],
credentials: true,
maxAge: 86_400,
});The plugin handles preflight requests and does not reflect an origin that is not allowed.
Static files
Static serving uses the official @elysiajs/static plugin. Configure it on the adapter:
const adapter = new ElysiaAdapter();
adapter.useStaticAssets({
assets: 'public',
prefix: '/assets',
indexHTML: true,
maxAge: 86_400,
});The legacy adapter.useStaticAssets('/assets', options) form is also supported.
GraphQL
Import GraphQL support only when the application needs it:
import { GraphQLModule } from '@nestjs/graphql';
import {
ElysiaGraphQLDriver,
type ElysiaGraphQLDriverConfig,
} from 'elysia-nestjs/graphql';
@Module({
imports: [
GraphQLModule.forRoot<ElysiaGraphQLDriverConfig>({
driver: ElysiaGraphQLDriver,
autoSchemaFile: true,
path: '/graphql',
context: ({ req, res }) => ({ req, res }),
}),
],
})
export class AppModule {}The driver supports GraphQL HTTP queries, mutations, contexts, Apollo errors, and incremental HTTP responses.
Subscriptions with graphql-ws
Subscriptions use the graphql-ws protocol only. It is registered directly on Elysia's WebSocket hooks, so it works with Bun and Elysia's Node adapter without a Node HTTP-server bridge.
GraphQLModule.forRoot<ElysiaGraphQLDriverConfig>({
driver: ElysiaGraphQLDriver,
autoSchemaFile: true,
path: '/graphql',
subscriptions: {
'graphql-ws': {
path: '/graphql',
connectionInitWaitTimeout: 5_000,
},
},
});The subscription server starts as part of the GraphQL driver and closes active sockets during Nest shutdown. Configure clients with graphql-ws and the graphql-transport-ws subprotocol. Nest recommends this protocol instead of the legacy transport; see the Nest subscription guide.
Optional uploads
REST multipart interceptors and the GraphQL Upload scalar live in the optional entry point:
import {
FileInterceptor,
GraphQLUpload,
UploadedFile,
} from 'elysia-nestjs/uploads';Use the REST helpers with normal Nest interceptors. For GraphQL, add GraphQLUpload to your resolvers, use Upload in the schema, and opt in to multipart parsing:
import { graphQLUploadParser } from 'elysia-nestjs/uploads';
GraphQLModule.forRoot<ElysiaGraphQLDriverConfig>({
driver: ElysiaGraphQLDriver,
uploadParser: graphQLUploadParser,
});Upload code is not imported by the HTTP or GraphQL entry points unless it is explicitly requested.
Limitations
- View engines are not supported.
- Only
graphql-wsis supported for subscriptions;subscriptions-transport-wsis intentionally not installed. - The adapter exposes Fetch-style requests, not Express request/response objects. Express-specific middleware should be replaced with Nest middleware or Elysia-compatible code.
- Uploads are optional and are not part of the core request path.
Troubleshooting
- Node does not listen: pass
adapter: node()from@elysia/nodetoElysiaAdapter. - CORS configuration has no effect: use
methodsandallowedHeaders, the official Elysia CORS option names, rather than Express aliases. - Subscription client disconnects immediately: use a
graphql-wsclient andgraphql-transport-ws; do not configure the legacy protocol. - Webhook signature verification fails: enable raw-body capture before creating the Nest application.
Development and publishing
bun install
bun run verify