Elysia Web Framework
Elysia is a high-performance, ergonomic web framework built specifically for the Bun runtime, emphasizing end-to-end type safety and an exceptional developer experience. It provides a comprehensive set of features for building web servers and APIs, including robust routing, middleware, declarative schema validation (powered by `@sinclair/typebox`), and integrated WebSocket support. The framework is currently stable at version 1.4.28 and maintains a rapid release cadence, frequently incorporating improvements and bug fixes, often in synergy with Bun's development. Its core differentiators include native integration with Bun for superior performance, extensive TypeScript support providing compile-time and runtime type integrity, and a strong focus on developer productivity. Elysia aims to offer a unified type system where types serve as a single source of truth across the application, from API definition to automatic documentation generation, streamlining development and reducing errors.
Common errors
-
Error: Cannot find module 'elysia'
cause This typically occurs when trying to run an Elysia application with `node` instead of `bun`, or if using CommonJS `require()` syntax with a package that is ESM-only.fixEnsure you are running your application with `bun run <your_file.ts>` or `bun start`. If using TypeScript, ensure your `tsconfig.json` targets `ESNext` modules. Always use `import` statements for Elysia. -
Elysia is not a constructor
cause This error arises when attempting to instantiate Elysia using `new Elysia()` after importing it incorrectly, often with a CommonJS `require()` statement that doesn't resolve the default export correctly, or if bundlers misinterpret the import.fixVerify that you are using an ESM import: `import { Elysia } from 'elysia'`. If this persists, check your `tsconfig.json`'s `module` and `moduleResolution` settings (e.g., `"module": "ESNext", "moduleResolution": "bundler"` or `"node16"`). -
Validation Error: 'body.name' expected string, received undefined
cause This error indicates that an incoming request body failed schema validation. In this example, the `name` property within the request body was expected to be a string but was either missing or of an incorrect type.fixCheck the incoming request's JSON body to ensure it matches the `t.Object` schema defined for the route. For this error, the request body should be `{"name": "some string"}`. -
Failed to listen on port 3000. Address already in use.
cause Another process is already using the specified port (e.g., 3000). This is a common operating system error.fixChange the port number in your `.listen()` call (e.g., `app.listen(4000)`). Alternatively, identify and terminate the process currently using the port (e.g., `lsof -i :3000` on Unix-like systems, `netstat -ano | findstr :3000` on Windows).
Warnings
- breaking Elysia 1.4.19 introduced a security fix that rejects invalid cookie signatures when using cookie rotation. This change, while enhancing security, may cause issues with clients using previously signed but now invalid cookies.
- gotcha When mounting Elysia instances using the `.group` or `.use` methods, incorrect URL path resolution can occur, especially with instances that have a `prefix` option or specific trailing path configurations. This could lead to routes not being matched as expected.
- gotcha Dynamic imports located within `.guard` functions might not register routes correctly, leading to routes being inaccessible or not applying their guards as intended. This was a known bug in earlier 1.x versions.
- gotcha Elysia is primarily optimized for and runs on the Bun runtime. While it may run on Node.js with some polyfills or compatibility layers, performance and certain features (like native file streaming) are best experienced with Bun. Many community plugins are also Bun-specific.
Install
-
npm install elysia -
yarn add elysia -
pnpm add elysia
Imports
- Elysia
const Elysia = require('elysia'); // Elysia is ESM-only and Bun-native new Elysia(); // Incorrect instantiation, it's a classimport { Elysia } from 'elysia' - t
import { Type } from '@sinclair/typebox'; // While TypeBox, Elysia re-exports its own 't'import { t } from 'elysia' - handle
import { handle } from 'elysia'
Quickstart
import { Elysia, t } from 'elysia'
const app = new Elysia()
.get('/', () => 'Hello Elysia!')
.post('/greet', ({ body }) => `Hello, ${body.name}!`, {
body: t.Object({
name: t.String({
minLength: 1,
description: 'The name of the person to greet.'
})
}),
detail: {
summary: 'Greets a person by name',
description: 'Accepts a JSON body with a `name` property and returns a greeting.'
}
})
.ws('/chat', {
message(ws, message) {
ws.send(`Echo: ${message}`);
},
open(ws) {
console.log('WebSocket client connected');
ws.send('Welcome to the chat!');
},
close() {
console.log('WebSocket client disconnected');
}
})
.listen(3000, () => {
console.log(`🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}`);
});
export type App = typeof app;