Skip to content

At glance ​

Elysia is designed with familiar API from Express and Fastify with extensive support for TypeScript, modern JavaScript API, and optimized for Bun.

Here's a simple hello world in Elysia.

typescript
import { Elysia } from 'elysia'

new Elysia()
	.get('/', () => 'Hello Elysia')
	.listen(3000)
import { Elysia } from 'elysia'

new Elysia()
	.get('/', () => 'Hello Elysia')
	.listen(3000)

Navigate to localhost:3000 and it should show 'Hello Elysia' as a result.

Performance ​

Building on Bun and extensive optimization like Static Code Analysis allows Elysia to generate optimized code on the fly.

Elysia can outperform most of the web frameworks available today[1], and even match the performance of Golang and Rust framework[2].

FrameworkRuntimeAveragePlain TextDynamic ParametersJSON Body
Elysiabun275,063.507326,868.9261,729.3236,592.32
Bunbun273,634.127322,071.07251,679.46247,151.85
Honobun257,532.08320,757.07233,769.22218,069.95
Web Standardbun242,838.703288,692.76226,591.45213,231.9
Hyper Expressnode242,045.913354,697.63277,109.5194,330.6
h3node112,677.263137,556.49101,431.599,043.8
Fastifynode64,145.9574,631.4666,235.4851,570.91
Koanode38,696.1344,741.8839,790.1131,556.4
Hapinode28,170.76342,780.4415,350.0626,381.79
Adonisnode23,367.07322,673.5421,442.9725,984.71
Expressnode16,301.82317,974.3517,090.6213,840.5
Nestnode14,978.86316,926.0115,507.6212,502.96

TypeScript ​

Elysia is built with a complex type system trying to infer every possible detail from simple path parameters to full-blown recursive instance deep merge to provide you the most out of TypeScript.

Take a look at this example:

typescript
import { Elysia } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id)
    .listen(3000)
import { Elysia } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id)
    .listen(3000)

The above code allows you to create a path parameter with the name of id, the value that passes after /id/ will be reflected in params.id.

In most framework, you need to provide a generic type to the id parameter while Elysia understand that params.id will always be available and type as string. Elysia then infers this type without any manual type reference needed.

Elysia's goal is to help you write less TypeScript and focus more on Business logic. Let the complex type be handled by the framework.

Unified Type ​

To take a step further, Elysia provide Elysia.t, a schema builder to validate type and value in both runtime and compile-time to create a single source of truth for your data-type. Elysia refers this term as Unified Type.

Let's modify the previous code to accept only a numeric value instead of a string.

typescript
import { Elysia, t } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)
import { Elysia, t } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)

This code ensures that our path parameter id, will always be a numeric string and then transform to a number automatically in both runtime and compile-time (type-level).

With Elysia schema builder, we can ensure type safety like a strong-typed language with a single source of truth.

Standard ​

Elysia adopts many standards by default, like OpenAPI, and WinterCG compliance, allowing you to integrate with most of the industry standard tools or at least easily integrate with tools you are familiar with.

For instance, as Elysia adopts OpenAPI by default, generating a documentation with Swagger is as easy as adding a one-liner:

typescript
import { Elysia, t } from 'elysia'
import { swagger } from '@elysiajs/swagger'

new Elysia()
    .use(swagger())
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)
import { Elysia, t } from 'elysia'
import { swagger } from '@elysiajs/swagger'

new Elysia()
    .use(swagger())
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)

With the Swagger plugin, you can seamlessly generate a Swagger page without additional code or specific config and share it with your team effortlessly.

End-to-end Type Safety ​

With Elysia, type safety is not only limited to server-side only.

With Elysia, you can synchronize your type with your frontend team automatically like tRPC, with Elysia's client library, "Eden".

typescript
import { Elysia, t } from 'elysia'
import { swagger } from '@elysiajs/swagger'

const app = new Elysia()
    .use(swagger())
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)

export type App = typeof app
import { Elysia, t } from 'elysia'
import { swagger } from '@elysiajs/swagger'

const app = new Elysia()
    .use(swagger())
    .get('/id/:id', ({ params: { id } }) => id, {
        params: t.Object({
            id: t.Numeric()
        })
    })
    .listen(3000)

export type App = typeof app

And on your client-side:

typescript
// client.ts
import { edenTreaty } from '@elysiajs/eden'
import type { App } from './server'

const app = edenTreaty<App>('http://localhost:3000')

// data is typed as number
const { data } = await app.id['177013'].get()
// client.ts
import { edenTreaty } from '@elysiajs/eden'
import type { App } from './server'

const app = edenTreaty<App>('http://localhost:3000')

// data is typed as number
const { data } = await app.id['177013'].get()

With Eden, you can use the existing Elysia type to query Elysia server without code generation and synchronize type for both frontend and backend automatically.

Elysia is not only about helping you to create a confident backend but for all that is beautiful in this world.


1. Measure in requests/second. The benchmark for parsing query, path parameter and set response header on Debian 11, Intel i7-13700K tested on Bun 0.7.2 on 6 Aug 2023. See the benchmark condition here.

2. Based on TechEmpower Benchmark round 22.