
A quick guide to integrating Elysia as your API layer inside an Astro project
Bryan Ferreira
Basically, you get a Bun powered API, end-to-end type safe via Eden Treaty, with automatic OpenAPI docs, and minimal config.
For the full reference, check the official Elysia + Astro docs.
Check the official setup guide to create a new Astro project if you don't have one already.
// astro.config.mjs
import { defineConfig } from "astro/config";
export default defineConfig({
output: "server",
});
bun add elysia @elysiajs/eden
Create a file in src/pages/ that catches every /api/* request and hands it off to Elysia.
// src/pages/[...slugs].ts
import { Elysia } from "elysia";
const app = new Elysia({ prefix: "/api" })
.get("/health", () => ({ status: "ok" }))
.get("/hello", () => ({ message: "Hello from Elysia!" }));
const handle = app.handle;
export const GET = handle;
export const POST = handle;
export const PUT = handle;
export const PATCH = handle;
export const DELETE = handle;
export type App = typeof app;
Install the plugin:
bun add @elysiajs/openapi
Then plug it into your app. Use enabled: import.meta.env.DEV so the Swagger UI only shows up in development.
// src/pages/[...slugs].ts
import { Elysia } from "elysia";
import { openapi } from "@elysiajs/openapi";
const app = new Elysia({ prefix: "/api" })
.use(
openapi({
provider: "swagger-ui",
enabled: import.meta.env.DEV,
}),
)
.get("/health", () => ({ status: "ok" }))
.get("/hello", () => ({ message: "Hello from Elysia!" }));
Once running:
/api/openapiEden Treaty gives you full type safety when calling your API — no codegen needed.
// src/lib/eden.ts
import { treaty } from "@elysiajs/eden";
import type { App } from "../pages/[...slugs]";
export const client = treaty<App>(import.meta.env.PUBLIC_API_URL);
Set the variable in your .env file:
# .env
PUBLIC_API_URL=localhost:4321 # in dev, this points to your local Astro server
// src/pages/index.astro (frontmatter)
import { client } from "../lib/eden";
const { data } = await client.api.hello.get();
<h1>{data?.message}</h1>