Pushduck
Pushduck// S3 uploads for any framework

Quick Start

Get file uploads working in 3 simple steps. No overwhelming configuration, just the essentials.

Prefer automated setup? Use npx @pushduck/cli init for zero-config setup. This guide is for manual installation.

Install Pushduck

npm install pushduck

Create API Route

One file with your S3 config and upload route:

app/api/upload/route.ts
import { createUploadConfig } from 'pushduck/server';

const { s3 } = createUploadConfig()
  .provider("aws", {
    bucket: process.env.AWS_BUCKET_NAME!,
    region: process.env.AWS_REGION!,
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
  })
  .build();

const router = s3.createRouter({
  imageUpload: s3.image().maxFileSize('5MB'),
});

export const { GET, POST } = router.handlers;
export type AppRouter = typeof router;

Environment variables: Add your S3 credentials to .env.local. See Provider Setup for getting credentials.

Create Client & Use in Components

Create a reusable client and use it in your components:

lib/upload-client.ts
import { createUploadClient } from 'pushduck/client';
import type { AppRouter } from '@/app/api/upload/route';

export const upload = createUploadClient<AppRouter>({
  endpoint: '/api/upload'
});
app/upload-demo.tsx
'use client';

import { upload } from '@/lib/upload-client';

export function UploadDemo() {
  const { uploadFiles, files, isUploading } = upload.imageUpload();

  return (
    <div>
      <input
        type="file"
        multiple
        accept="image/*"
        onChange={(e) => uploadFiles(Array.from(e.target.files || []))}
        disabled={isUploading}
      />

      {files.map((file) => (
        <div key={file.id}>
          {file.name} - {file.progress}%
          {file.status === 'success' && <img src={file.url} alt={file.name} />}
        </div>
      ))}
    </div>
  );
}

✅ Done!

That's it - 3 steps, 3 files, ~40 lines of code, and you have production-ready file uploads!


Need More?

Next Steps