Hono
Fast, lightweight file uploads with Hono using Web Standards - no adapter needed!
Hono Integration
Hono is a fast, lightweight web framework built on Web Standards. Since Hono uses Request
and Response
objects natively, pushduck handlers work directly without any adapters!
Web Standards Native: Hono exposes c.req.raw
as a Web Standard Request
object, making pushduck integration seamless with zero overhead.
Quick Setup
Install dependencies
npm install pushduck
yarn add pushduck
pnpm add pushduck
bun 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 Hono app with upload routes
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload';
const app = new Hono();
// Direct usage - no adapter needed!
app.all('/api/upload/*', (c) => {
return uploadRouter.handlers(c.req.raw);
});
export default app;
Basic Integration
Simple Upload Route
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload';
const app = new Hono();
// Method 1: Combined handler (recommended)
app.all('/api/upload/*', (c) => {
return uploadRouter.handlers(c.req.raw);
});
// Method 2: Separate handlers (if you need method-specific logic)
app.get('/api/upload/*', (c) => uploadRouter.handlers.GET(c.req.raw));
app.post('/api/upload/*', (c) => uploadRouter.handlers.POST(c.req.raw));
export default app;
With Middleware
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { uploadRouter } from './lib/upload';
const app = new Hono();
// Global middleware
app.use('*', logger());
app.use('*', cors({
origin: ['http://localhost:3000', 'https://your-domain.com'],
allowMethods: ['GET', 'POST'],
allowHeaders: ['Content-Type'],
}));
// Upload routes
app.all('/api/upload/*', (c) => uploadRouter.handlers(c.req.raw));
// Health check
app.get('/health', (c) => c.json({ status: 'ok' }));
export default app;
Advanced Configuration
Authentication with Hono
import { createUploadConfig } from 'pushduck/server';
import { verify } from 'hono/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 {
const payload = await 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;
Deployment Options
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload';
const app = new Hono();
app.all('/api/upload/*', (c) => uploadRouter.handlers(c.req.raw));
export default app;
name = "my-upload-api"
main = "src/index.ts"
compatibility_date = "2023-12-01"
[env.production]
vars = { NODE_ENV = "production" }
# Deploy to Cloudflare Workers
npx wrangler deploy
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload';
const app = new Hono();
app.all('/api/upload/*', (c) => uploadRouter.handlers(c.req.raw));
export default {
port: 3000,
fetch: app.fetch,
};
# Run with Bun
bun run server.ts
import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload';
const app = new Hono();
app.all('/api/upload/*', (c) => uploadRouter.handlers(c.req.raw));
const port = 3000;
console.log(`Server is running on port ${port}`);
serve({
fetch: app.fetch,
port
});
# Run with Node.js
npm run dev
import { Hono } from 'hono';
import { uploadRouter } from './lib/upload.ts';
const app = new Hono();
app.all('/api/upload/*', (c) => uploadRouter.handlers(c.req.raw));
Deno.serve(app.fetch);
# Run with Deno
deno run --allow-net --allow-env server.ts
Performance Benefits
🚀 Zero Overhead
Direct Web Standards integration
No adapter layer means zero performance overhead - pushduck handlers run directly in Hono.
⚡ Fast Runtime
Hono's lightweight design
Hono is one of the fastest web frameworks, perfect for high-performance upload APIs.
🌐 Edge Ready
Deploy anywhere
Works on Cloudflare Workers, Bun, Node.js, and Deno with the same code.
📦 Small Bundle
Minimal dependencies
Hono + pushduck creates incredibly lightweight upload services.
Perfect Match: Hono's Web Standards foundation and pushduck's universal design create a powerful, fast, and lightweight file upload solution that works everywhere.