Bun Runtime
Ultra-fast JavaScript runtime with native Web Standards support - no adapter needed!
Using pushduck with Bun
Bun is an ultra-fast JavaScript runtime with native Web Standards support. Since Bun uses Web Standard Request and Response objects natively, pushduck handlers work directly without any adapters!
Web Standards Native: Bun's Bun.serve() uses Web Standard Request objects directly, making pushduck integration seamless with zero overhead.
Quick Setup
Install dependencies
bun add pushducknpm install pushduckyarn add pushduckpnpm add pushduckConfigure 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().maxFileSize("5MB"),
documentUpload: s3.file().maxFileSize("10MB")
});
export type AppUploadRouter = typeof uploadRouter;Create Bun server with upload routes
import { uploadRouter } from './lib/upload';
// Direct usage - no adapter needed!
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
if (url.pathname.startsWith('/api/upload/')) {
return uploadRouter.handlers(request);
}
return new Response('Not found', { status: 404 });
},
});
console.log('🚀 Bun server running on http://localhost:3000');Basic Integration
Simple Upload Server
import { uploadRouter } from './lib/upload';
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
// Method 1: Combined handler (recommended)
if (url.pathname.startsWith('/api/upload/')) {
return uploadRouter.handlers(request);
}
// Health check
if (url.pathname === '/health') {
return new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not found', { status: 404 });
},
});
console.log('🚀 Bun server running on http://localhost:3000');With CORS and Routing
import { uploadRouter } from './lib/upload';
function handleCORS(request: Request) {
const origin = request.headers.get('origin');
const allowedOrigins = ['http://localhost:3000', 'https://your-domain.com'];
const headers = new Headers();
if (origin && allowedOrigins.includes(origin)) {
headers.set('Access-Control-Allow-Origin', origin);
}
headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return headers;
}
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
const corsHeaders = handleCORS(request);
// Handle preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, { status: 200, headers: corsHeaders });
}
// Upload routes
if (url.pathname.startsWith('/api/upload/')) {
return uploadRouter.handlers(request).then(response => {
// Add CORS headers to response
corsHeaders.forEach((value, key) => {
response.headers.set(key, value);
});
return response;
});
}
// Health check
if (url.pathname === '/health') {
return new Response(JSON.stringify({
status: 'ok',
runtime: 'Bun',
timestamp: new Date().toISOString()
}), {
headers: {
'Content-Type': 'application/json',
...Object.fromEntries(corsHeaders)
}
});
}
return new Response('Not found', { status: 404 });
},
});
console.log('🚀 Bun server running on http://localhost:3000');Advanced Configuration
Authentication and Rate Limiting
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!,
})
.paths({
prefix: 'uploads',
generateKey: (file, metadata) => {
return `${metadata.userId}/${Date.now()}/${file.name}`;
}
})
.build();
export const uploadRouter = createS3Router({
// Private uploads with authentication
privateUpload: s3
.image()
.maxFileSize("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 {
const payload = await verifyJWT(token);
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()
.maxFileSize("2MB")
// No middleware = public access
});
async function verifyJWT(token: string) {
// Your JWT verification logic here
// Using Bun's built-in crypto or a JWT library
return { sub: 'user-123', role: 'user' };
}
export type AppUploadRouter = typeof uploadRouter;Production Server with Full Features
import { uploadRouter } from './lib/upload';
// Simple rate limiting store
const rateLimitStore = new Map<string, { count: number; resetTime: number }>();
function rateLimit(ip: string, maxRequests = 100, windowMs = 15 * 60 * 1000) {
const now = Date.now();
const key = ip;
const record = rateLimitStore.get(key);
if (!record || now > record.resetTime) {
rateLimitStore.set(key, { count: 1, resetTime: now + windowMs });
return true;
}
if (record.count >= maxRequests) {
return false;
}
record.count++;
return true;
}
function getClientIP(request: Request): string {
// In production, you might get this from headers like X-Forwarded-For
return request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') ||
'unknown';
}
Bun.serve({
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
fetch(request) {
const url = new URL(request.url);
const clientIP = getClientIP(request);
// Rate limiting
if (!rateLimit(clientIP)) {
return new Response(JSON.stringify({
error: 'Too many requests'
}), {
status: 429,
headers: { 'Content-Type': 'application/json' }
});
}
// CORS
const corsHeaders = {
'Access-Control-Allow-Origin': process.env.NODE_ENV === 'production'
? 'https://your-domain.com'
: '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
// Handle preflight
if (request.method === 'OPTIONS') {
return new Response(null, { status: 200, headers: corsHeaders });
}
// Upload routes
if (url.pathname.startsWith('/api/upload/')) {
return uploadRouter.handlers(request).then(response => {
Object.entries(corsHeaders).forEach(([key, value]) => {
response.headers.set(key, value);
});
return response;
}).catch(error => {
console.error('Upload error:', error);
return new Response(JSON.stringify({
error: 'Upload failed',
message: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error'
}), {
status: 500,
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
});
}
// API info
if (url.pathname === '/api') {
return new Response(JSON.stringify({
name: 'Bun Upload API',
version: '1.0.0',
runtime: 'Bun',
endpoints: {
health: '/health',
upload: '/api/upload/*'
}
}), {
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
// Health check
if (url.pathname === '/health') {
return new Response(JSON.stringify({
status: 'ok',
runtime: 'Bun',
version: Bun.version,
timestamp: new Date().toISOString(),
uptime: process.uptime()
}), {
headers: {
'Content-Type': 'application/json',
...corsHeaders
}
});
}
return new Response('Not found', { status: 404, headers: corsHeaders });
},
});
console.log(`🚀 Bun server running on http://localhost:${process.env.PORT || 3000}`);
console.log(`📊 Environment: ${process.env.NODE_ENV || 'development'}`);File-based Routing
Structured Application
import { uploadRouter } from '../lib/upload';
export function handleUpload(request: Request) {
return uploadRouter.handlers(request);
}export function handleAPI(request: Request) {
return new Response(JSON.stringify({
name: 'Bun Upload API',
version: '1.0.0',
runtime: 'Bun'
}), {
headers: { 'Content-Type': 'application/json' }
});
}import { handleUpload } from './routes/upload';
import { handleAPI } from './routes/api';
const routes = {
'/api/upload': handleUpload,
'/api': handleAPI,
'/health': () => new Response(JSON.stringify({ status: 'ok' }), {
headers: { 'Content-Type': 'application/json' }
})
};
Bun.serve({
port: 3000,
fetch(request) {
const url = new URL(request.url);
for (const [path, handler] of Object.entries(routes)) {
if (url.pathname.startsWith(path)) {
return handler(request);
}
}
return new Response('Not found', { status: 404 });
},
});Performance Benefits
🚀 Ultra-Fast Runtime
Bun's exceptional performance
Bun is 3x faster than Node.js, providing incredible performance for file upload operations.
⚡ Zero Overhead
Direct Web Standards integration
No adapter layer means zero performance overhead - pushduck handlers run directly in Bun.
📦 Built-in Features
Batteries included
Built-in bundler, test runner, package manager, and more - no extra tooling needed.
🔧 Native TypeScript
First-class TypeScript support
Run TypeScript directly without compilation, perfect for rapid development.
Deployment
Docker 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"]Production Scripts
{
"name": "bun-upload-server",
"version": "1.0.0",
"scripts": {
"dev": "bun run --watch server.ts",
"start": "bun run server.ts",
"build": "bun build server.ts --outdir ./dist --target bun",
"test": "bun test"
},
"dependencies": {
"pushduck": "latest"
},
"devDependencies": {
"bun-types": "latest"
}
}Bun + Pushduck: The perfect combination for ultra-fast file uploads with zero configuration overhead and exceptional developer experience.