Documentation Index
Fetch the complete documentation index at: https://mintlify.com/elysiajs/documentation/llms.txt
Use this file to discover all available pages before exploring further.
With the Next.js App Router, you can run Elysia directly inside route handler files. Because Elysia is WinterTC-compliant, it works with the same Request/Response primitives that Next.js route handlers use — no additional adapter needed.
Create a catch-all route file
Create app/api/[[...slugs]]/route.ts in your Next.js project.
Define your Elysia server and export HTTP method handlers
// app/api/[[...slugs]]/route.ts
import { Elysia, t } from 'elysia'
const app = new Elysia({ prefix: '/api' })
.get('/', 'Hello Nextjs')
.post('/', ({ body }) => body, {
body: t.Object({
name: t.String()
})
})
export const GET = app.fetch
export const POST = app.fetch
Route prefix
If you place your Elysia server in a subdirectory (e.g. app/user/[[...slugs]]/route.ts), you must set the prefix option to match the directory path:
// app/user/[[...slugs]]/route.ts
import { Elysia, t } from 'elysia'
const app = new Elysia({ prefix: '/user' })
.get('/', 'Hello Nextjs')
.post('/', ({ body }) => body, {
body: t.Object({
name: t.String()
})
})
export const GET = app.fetch
export const POST = app.fetch
End-to-end type safety with Eden
You can add Eden Treaty for end-to-end type safety between your Next.js frontend and Elysia backend. The isomorphic fetch pattern lets Eden call Elysia directly on the server without a network round-trip, and through the network on the client.
Export your Elysia instance
// app/api/[[...slugs]]/route.ts
import { Elysia } from 'elysia'
export const app = new Elysia({ prefix: '/api' })
.get('/', 'Hello Nextjs')
export const GET = app.fetch
export const POST = app.fetch
Create an isomorphic Treaty client
// lib/eden.ts
import { treaty } from '@elysia/eden'
import type { app } from '../app/api/[[...slugs]]/route'
// Use typeof process instead of typeof window — window is undefined at build time
export const api =
typeof process !== 'undefined'
? treaty(app).api
: treaty<typeof app>('localhost:3000').api
Use the client in server and client components
// app/page.tsx
import { api } from '../lib/eden'
export default async function Page() {
const message = await api.get()
return <h1>Hello, {message}</h1>
}
Use typeof process rather than typeof window to distinguish server from client. The window object is undefined at build time and will cause hydration errors.
pnpm peer dependencies
If you use pnpm, install peer dependencies manually:
pnpm add @sinclair/typebox openapi-types