Skip to main content

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.
1

Create a catch-all route file

Create app/api/[[...slugs]]/route.ts in your Next.js project.
2

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.
1

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
2

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
3

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
See Next.js Route Handlers for further reference on the underlying routing mechanism.

Build docs developers (and LLMs) love