Elysia
TypeScript-first framework with Bun - Web Standards native, no adapter needed!
Elysia
Elysia is a TypeScript-first web framework designed for Bun. Since Elysia uses Web Standard Request
objects natively, pushduck handlers work directly without any adapters!
Web Standards Native: Elysia exposes context.request
as a Web Standard Request
object, making pushduck integration seamless with zero overhead.
Quick Setup
Install dependencies
bun add pushduck
npm install pushduck
yarn add pushduck
pnpm add pushduck
Configure upload router
import { createUploadConfig } from 'pushduck/server';
const { s3, createS3Router } = createUploadConfig()
.provider("cloudflareR2",{
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
region: 'auto',
endpoint: process.env.AWS_ENDPOINT_URL!,
bucket: process.env.S3_BUCKET_NAME!,
accountId: process.env.R2_ACCOUNT_ID!,
})
.build();
export const uploadRouter = createS3Router({
imageUpload: s3.image().max("5MB"),
documentUpload: s3.file().max("10MB")
});
export type AppUploadRouter = typeof uploadRouter;
Create Elysia app with upload routes
import { Elysia } from 'elysia';
import { uploadRouter } from './lib/upload';
const app = new Elysia();
// Direct usage - no adapter needed!
app.all('/api/upload/*', (context) => {
return uploadRouter.handlers(context.request);
});
app.listen(3000);
Basic Integration
Simple Upload Route
import { Elysia } from 'elysia';
import { uploadRouter } from './lib/upload';
const app = new Elysia();
// Method 1: Combined handler (recommended)
app.all('/api/upload/*', (context) => {
return uploadRouter.handlers(context.request);
});
// Method 2: Separate handlers (if you need method-specific logic)
app.get('/api/upload/*', (context) => uploadRouter.handlers.GET(context.request));
app.post('/api/upload/*', (context) => uploadRouter.handlers.POST(context.request));
app.listen(3000);
With Middleware and CORS
import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { uploadRouter } from './lib/upload';
const app = new Elysia()
.use(cors({
origin: ['http://localhost:3000', 'https://your-domain.com'],
allowedHeaders: ['Content-Type', 'Authorization'],
methods: ['GET', 'POST']
}))
// Upload routes
.all('/api/upload/*', (context) => uploadRouter.handlers(context.request))
// Health check
.get('/health', () => ({ status: 'ok' }))
.listen(3000);
console.log(`🦊 Elysia is running at http://localhost:3000`);
Advanced Configuration
Authentication with JWT
import { createUploadConfig } from 'pushduck/server';
import jwt from '@elysiajs/jwt';
const { s3, createS3Router } = createUploadConfig()
.provider("cloudflareR2",{
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
region: 'auto',
endpoint: process.env.AWS_ENDPOINT_URL!,
bucket: process.env.S3_BUCKET_NAME!,
accountId: process.env.R2_ACCOUNT_ID!,
})
.paths({
prefix: 'uploads',
generateKey: (file, metadata) => {
return `${metadata.userId}/${Date.now()}/${file.name}`;
}
})
.build();
export const uploadRouter = createS3Router({
// Private uploads with JWT authentication
privateUpload: s3
.image()
.max("5MB")
.middleware(async ({ req }) => {
const authHeader = req.headers.get('authorization');
if (!authHeader?.startsWith('Bearer ')) {
throw new Error('Authorization required');
}
const token = authHeader.substring(7);
try {
// Use your JWT verification logic here
const payload = jwt.verify(token, process.env.JWT_SECRET!);
return {
userId: payload.sub as string,
userRole: payload.role as string
};
} catch (error) {
throw new Error('Invalid token');
}
}),
// Public uploads (no auth)
publicUpload: s3
.image()
.max("2MB")
// No middleware = public access
});
export type AppUploadRouter = typeof uploadRouter;
Full Production Setup
import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { rateLimit } from '@elysiajs/rate-limit';
import { swagger } from '@elysiajs/swagger';
import { uploadRouter } from './lib/upload';
const app = new Elysia()
// Swagger documentation
.use(swagger({
documentation: {
info: {
title: 'Upload API',
version: '1.0.0'
}
}
}))
// CORS
.use(cors({
origin: process.env.NODE_ENV === 'production'
? ['https://your-domain.com']
: true,
allowedHeaders: ['Content-Type', 'Authorization'],
methods: ['GET', 'POST']
}))
// Rate limiting
.use(rateLimit({
max: 100,
windowMs: 15 * 60 * 1000, // 15 minutes
}))
// Upload routes
.all('/api/upload/*', (context) => uploadRouter.handlers(context.request))
// Health check
.get('/health', () => ({
status: 'ok',
timestamp: new Date().toISOString()
}))
.listen(process.env.PORT || 3000);
console.log(`🦊 Elysia is running at http://localhost:${process.env.PORT || 3000}`);
TypeScript Integration
Type-Safe Client
import { createUploadClient } from 'pushduck/client';
import type { AppUploadRouter } from './upload';
export const uploadClient = createUploadClient<AppUploadRouter>({
baseUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'
});
Client Usage
import { uploadClient } from '../lib/upload-client';
export function UploadComponent() {
const handleUpload = async (files: File[]) => {
try {
const results = await uploadClient.upload('imageUpload', {
files,
// Type-safe metadata based on your router configuration
metadata: { userId: 'user-123' }
});
console.log('Upload successful:', results);
} catch (error) {
console.error('Upload failed:', error);
}
};
return (
<input
type="file"
multiple
onChange={(e) => {
if (e.target.files) {
handleUpload(Array.from(e.target.files));
}
}}
/>
);
}
Performance Benefits
🚀 Zero Overhead
Direct Web Standards integration
No adapter layer means zero performance overhead - pushduck handlers run directly in Elysia.
⚡ Bun Performance
Ultra-fast JavaScript runtime
Built for Bun's exceptional performance, perfect for high-throughput upload APIs.
📝 TypeScript First
End-to-end type safety
Full TypeScript support from server to client with compile-time safety.
🔧 Plugin Ecosystem
Rich middleware support
Extensive plugin ecosystem for authentication, validation, rate limiting, and more.
Deployment
Production Deployment
FROM oven/bun:1 as base
WORKDIR /usr/src/app
# Install dependencies
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Run the app
CMD ["bun", "run", "server.ts"]
# Build and run
docker build -t my-upload-api .
docker run -p 3000:3000 my-upload-api
Perfect TypeScript Integration: Elysia's TypeScript-first approach combined with pushduck's type-safe design creates an exceptional developer experience with full end-to-end type safety.