@pushduck/cli
v0.2.1
Published
Official CLI for pushduck - Add S3 upload functionality to your Next.js project
Maintainers
Readme
Pushduck CLI
Zero-configuration setup for Next.js file uploads. Get production-ready S3 uploads working in under 2 minutes.
Quick Start
npx @pushduck/cli@latest initThat's it! The CLI will guide you through setting up:
- ✅ Provider configuration (AWS S3, Cloudflare R2, etc.)
- ✅ API route generation with TypeScript
- ✅ Example upload components
- ✅ Environment variable setup
- ✅ Bucket creation (optional)
Commands
init - Initialize Your Project
npx @pushduck/cli@latest init [options]Options:
--provider <type>- Skip provider selection (aws|cloudflare-r2|digitalocean|minio|gcs)--skip-examples- Don't generate example components--skip-bucket- Don't create S3 bucket automatically--api-path <path>- Custom API route path (default:/api/upload)--dry-run- Show what would be created without creating--verbose- Show detailed output
Examples:
# Interactive setup with all prompts
npx @pushduck/cli@latest init
# Use AWS S3 directly, skip examples
npx @pushduck/cli@latest init --provider aws --skip-examples
# Custom API path
npx @pushduck/cli@latest init --api-path /api/files
# Preview without creating files
npx @pushduck/cli@latest init --dry-runadd - Add Upload Routes
npx @pushduck/cli@latest addAdd new upload routes to your existing configuration. Interactive route builder helps you:
- Define file types and validation
- Set up middleware and authentication
- Configure upload destinations
- Generate TypeScript types
test - Validate Setup
npx @pushduck/cli@latest test [--verbose]Validates your current configuration:
- ✅ Environment variables
- ✅ S3 bucket connectivity
- ✅ CORS configuration
- ✅ API route functionality
- ✅ TypeScript compilation
What Gets Created
The CLI generates a complete, production-ready setup:
your-project/
├── app/api/upload/route.ts # Type-safe upload API
├── app/upload/page.tsx # Demo upload page
├── components/ui/
│ ├── upload-button.tsx # Simple upload button
│ ├── upload-dropzone.tsx # Drag & drop component
│ └── file-preview.tsx # File preview component
├── lib/upload-client.ts # Type-safe upload client
├── .env.local # Environment variables
└── .env.example # Environment templateGenerated API Route
// app/api/upload/route.ts
import { createUploadRouter, uploadSchema } from 'pushduck/server'
export const router = createUploadRouter({
imageUpload: uploadSchema({
image: {
maxSize: "5MB",
maxCount: 1,
formats: ["jpeg", "png", "webp"]
}
}).middleware(async ({ req }) => {
// Add your authentication logic
const userId = await getUserId(req)
return { userId, folder: `uploads/${userId}` }
}),
documentUpload: uploadSchema({
file: {
maxSize: "10MB",
maxCount: 5,
allowedTypes: ["application/pdf", "text/plain"]
}
}).middleware(async ({ req }) => {
const userId = await getUserId(req)
return { userId, folder: `documents/${userId}` }
})
})
export type AppRouter = typeof router
export const { GET, POST } = routerGenerated Upload Client
// 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'
})
// Property-based access with full type safety
export const { imageUpload, documentUpload } = uploadGenerated Components
// components/ui/upload-button.tsx
'use client'
import { upload } from '@/lib/upload-client'
export function UploadButton() {
const { uploadFiles, uploadedFiles, isUploading, progress } = upload.imageUpload()
return (
<div>
<input
type="file"
onChange={(e) => uploadFiles(e.target.files)}
disabled={isUploading}
/>
{isUploading && <div>Progress: {progress}%</div>}
{uploadedFiles.map(file => (
<img key={file.key} src={file.url} alt="Uploaded" />
))}
</div>
)
}Provider Support
The CLI supports all major S3-compatible providers:
- AWS S3 - The original and most feature-complete
- Cloudflare R2 - Global edge network, S3-compatible
- DigitalOcean Spaces - Simple and affordable
- Google Cloud Storage - Enterprise-grade with global reach
- MinIO - Self-hosted, open source S3 alternative
Provider-Specific Setup
Each provider has tailored setup:
# AWS S3 with automatic IAM policy creation
npx @pushduck/cli@latest init --provider aws
# Cloudflare R2 with edge optimization
npx @pushduck/cli@latest init --provider cloudflare-r2
# DigitalOcean Spaces with CDN setup
npx @pushduck/cli@latest init --provider digitalocean
# MinIO for local development
npx @pushduck/cli@latest init --provider minioInteractive Setup Flow
The CLI provides a guided setup experience:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 🚀 Welcome to Pushduck │
│ │
│ Let's get your file uploads working in 2 minutes! │
│ │
└─────────────────────────────────────────────────────────────┘
🔍 Detecting your project...
✓ Next.js App Router detected
✓ TypeScript configuration found
✓ No existing upload configuration
? Which cloud storage provider would you like to use?
❯ AWS S3 (recommended)
Cloudflare R2 (S3-compatible, global edge)
DigitalOcean Spaces (simple, affordable)
🔧 Setting up AWS S3...
🔍 Checking for existing credentials...
✓ Found AWS_ACCESS_KEY_ID
✓ Found AWS_SECRET_ACCESS_KEY
✓ Found AWS_REGION
? Enter your S3 bucket name: my-app-uploads
? Create bucket automatically? Yes
🛠️ Generating files...
✨ Created files:
├── app/api/upload/route.ts
├── app/upload/page.tsx
├── components/ui/upload-button.tsx
├── lib/upload-client.ts
└── .env.example
📦 Installing dependencies...
✓ pushduck
✓ react-dropzone
🎉 Setup complete! Your uploads are ready.Troubleshooting
CLI Not Found
# If you get "command not found"
npm install -g pushduck
# Or use npx for one-time usage
npx @pushduck/cli@latest@latest initPermission Errors
# If you get permission errors during setup
sudo npx @pushduck/cli@latest init
# Or fix npm permissions
npm config set prefix ~/.npm-global
export PATH=~/.npm-global/bin:$PATHBucket Creation Failed
# Test your credentials first
npx @pushduck/cli@latest test
# Skip automatic bucket creation
npx @pushduck/cli@latest init --skip-bucket
# Create bucket manually, then run:
npx @pushduck/cli@latest testAdvanced Usage
Non-Interactive Mode
# For CI/CD environments
npx @pushduck/cli@latest init \
--provider aws \
--skip-examples \
--api-path /api/upload \
--no-interactiveCustom Templates
# Use enterprise template with security features
npx @pushduck/cli@latest init --template enterprise
# Use minimal template for existing projects
npx @pushduck/cli@latest init --template minimalMonorepo Support
# For monorepos, specify the Next.js app directory
cd apps/web
npx @pushduck/cli@latest init
# Or use the --cwd flag
npx @pushduck/cli@latest init --cwd apps/webContributing
The CLI is part of the pushduck monorepo.
# Clone the repository
git clone https://github.com/your-org/pushduck.git
# Install dependencies
pnpm install
# Development
cd packages/cli
pnpm dev
# Build
pnpm build
# Test locally
npm link
pushduck initLicense
MIT © Abhay Ramesh
