Making Elysia accessible for soydevs & triangle enthusiasts.
work in progress - do NOT use this for anything important (yet) :3
- Compatible
NextRequest,NextResponse,cookies(),headers()APIs - Create full-fledged Elysia projects from your NextJS api.
- Aiming to be a drop-in replacement for NextJS's API server
- Adding the NextJS sugar, and DX to Elysia :3
- Next.js App Router file-based routing conventions
- TypeScript support with Eden Treaty integration
- Runtime mode for dev, compiled mode for production
- OpenAPI/Swagger generation from TypeBox schemas
- Supports*
next.config.tsandmiddleware.ts
| Package | Description |
|---|---|
foxen |
Meta package - batteries included |
@foxen/core |
NextRequest, NextResponse, cookies, headers |
@foxen/helpers |
userAgent, geolocation, IP detection |
@foxen/adapter |
Runtime Elysia plugin |
@foxen/compiler |
Code generation with ts-morph |
@foxen/cli |
CLI tools (init, dev, generate, migrate) |
@foxen/config |
Configuration + next.config.ts support |
@foxen/middleware |
middleware.ts support |
@foxen/env |
.env loader with type-safety & added sugar |
@foxen/navigation |
next/navigation sugar, like rewrites, interupts, headersm cookies |
@foxen/auth |
Opt-in auth helpers built on better-auth |
# Install the meta package (includes everything)
bun add foxn elysia
# Or install individual packages
bun add @foxen/cli @foxen/adapter @foxen/core elysiabunx foxn init// src/app/api/hello/route.ts
import { NextRequest, NextResponse } from '@foxen/core';
export async function GET(request: NextRequest) {
return NextResponse.json({ message: 'Hello from Foxen!' });
}bunx foxn devRequires installing @foxen/auth alongside better-auth:
bun add @foxen/auth better-authSample usage for protecting routes:
// src/app/api/secure/route.ts
import { NextRequest, NextResponse } from '@foxen/core';
import { requireAuth, CommonChecks, createBetterAuthSessionGetter } from '@foxen/auth';
import { auth } from './better-auth-instance';
const getSession = createBetterAuthSessionGetter(auth);
export async function GET(request: NextRequest) {
const { session } = await requireAuth(request, getSession)
.addCheck(CommonChecks.hasRole('admin'))
.execute();
return NextResponse.json({ userId: session.userId, ok: true });
}bunx foxn generateLoad routes dynamically at runtime - perfect for development:
import { Elysia } from 'elysia';
import { appRouter } from '@foxen/adapter';
const app = new Elysia()
.use(await appRouter({
apiDir: './src/app/api',
middlewarePath: './middleware.ts',
nextConfigPath: './next.config.ts',
}))
.listen(3000);
console.log('Server running on http://localhost:3000');Generate optimized Elysia routes with full type safety:
import { Elysia } from 'elysia';
import { router } from './generated/router';
const app = new Elysia()
.use(router)
.listen(3000);
// Export type for Eden Treaty
export type App = typeof app;Routes work exactly like Next.js App Router:
// src/app/api/users/route.ts
import { NextRequest, NextResponse } from '@foxen/core';
export async function GET(request: NextRequest) {
const page = request.nextUrl.searchParams.get('page') ?? '1';
const users = await getUsers({ page: parseInt(page) });
return NextResponse.json({ users });
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await createUser(body);
return NextResponse.json(user, { status: 201 });
}// src/app/api/users/[id]/route.ts
import { NextRequest, NextResponse } from '@foxen/core';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const user = await getUser(id);
if (!user) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
return NextResponse.json(user);
}// src/app/api/docs/[...slug]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ slug: string[] }> }
) {
const { slug } = await params;
// slug = ['guides', 'getting-started'] for /api/docs/guides/getting-started
return NextResponse.json({ path: slug.join('/') });
}// middleware.ts
import { NextRequest, NextResponse } from '@foxen/core';
export function middleware(request: NextRequest) {
const token = request.cookies.get('token');
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const response = NextResponse.next();
response.headers.set('X-Request-ID', crypto.randomUUID());
return response;
}
export const config = {
matcher: '/api/:path*',
};import { defineConfig } from '@foxen/cli';
export default defineConfig({
routesDir: './src/app/api',
outputDir: './src/generated',
basePath: '/api',
format: 'ts',
generateBarrel: true,
});Foxen supports next.config.ts features like redirects, rewrites, and headers:
// next.config.ts
export default {
async redirects() {
return [
{ source: '/old-api/:path*', destination: '/api/:path*', permanent: true },
];
},
async rewrites() {
return [
{ source: '/v1/users', destination: '/api/users' },
];
},
async headers() {
return [
{
source: '/api/:path*',
headers: [
{ key: 'X-Powered-By', value: 'Foxen' },
],
},
];
},
};Add schemas for OpenAPI documentation and end-to-end type safety:
// src/app/api/users/route.ts
import { NextRequest, NextResponse } from '@foxen/core';
import { t } from 'elysia';
export async function GET(request: NextRequest) {
return NextResponse.json({ users: [] });
}
// Schema for OpenAPI + Eden Treaty
export const schema = {
GET: {
query: t.Object({
page: t.Optional(t.Number({ default: 1 })),
limit: t.Optional(t.Number({ default: 10 })),
}),
response: t.Object({
users: t.Array(t.Object({
id: t.String(),
name: t.String(),
email: t.String(),
})),
}),
tags: ['users'],
summary: 'List all users',
},
};| Command | Description |
|---|---|
foxen init |
Initialize foxen.config.ts |
foxen dev |
Start dev server with hot reload |
foxen dev --port 8080 |
Custom port |
foxen generate |
Generate optimized routes |
foxen generate --watch |
Watch mode |
foxen migrate <src> <dest> |
Migrate Next.js project |
foxen start |
Start server |
See the examples directory:
| Example | Description |
|---|---|
| basic | Simple routes with middleware and config |
| with-config | Redirects, rewrites, headers |
| with-middleware | Authentication middleware |
| with-swagger | OpenAPI/Swagger integration |
bun add foxn elysia- import { NextRequest, NextResponse } from 'next/server';
+ import { NextRequest, NextResponse } from '@foxen/core';// server.ts
import { Elysia } from 'elysia';
import { appRouter } from '@foxen/adapter';
const app = new Elysia()
.use(await appRouter({ apiDir: './src/app/api' }))
.listen(3000);bun run server.ts┌─────────────────────────────────────────────────────────┐
│ Your Application │
├─────────────────────────────────────────────────────────┤
│ app/api/ │
│ ├── users/route.ts → GET, POST /api/users │
│ └── users/[id]/route.ts → GET, PUT /api/users/:id │
├─────────────────────────────────────────────────────────┤
│ @foxen/compiler │
│ Analyzes → Generates optimized Elysia code │
├─────────────────────────────────────────────────────────┤
│ @foxen/adapter │
│ NextRequest/Response → Elysia context │
├─────────────────────────────────────────────────────────┤
│ @foxen/core │
│ 1:1-ish Next.js compatible: NextRequest, NextResponse │
├─────────────────────────────────────────────────────────┤
│ Elysia │
│ Type-safe, high-performance framework │
├─────────────────────────────────────────────────────────┤
│ Bun │
│ Fast JavaScript runtime │
└─────────────────────────────────────────────────────────┘
Contributions are welcome! Please open an issue or PR. (im begging you)
# Clone and install
git clone https://github.com/xwxfox/foxen.git
cd foxen
bun install
# Run tests
bun test
# Build all packages
bun run buildMIT