CLI Reference
Complete reference for the pushduck CLI tool with all commands, options, and examples
🚀 Recommended: Use our CLI for the fastest setup experience
Quick Start
Get your file uploads working in under 2 minutes with our interactive CLI tool.
npx @pushduck/cli@latest init
pnpm dlx pushduck init
yarn dlx pushduck init
bunx pushduck init
The CLI will automatically:
- 🔍 Detect your package manager (npm, pnpm, yarn, bun)
- 📦 Install dependencies using your preferred package manager
- ☁️ Set up your storage provider (Cloudflare R2, AWS S3, etc.)
- 🛠️ Generate type-safe code (API routes, client, components)
- ⚙️ Configure environment variables and bucket setup
What the CLI Does
Project Detection
Automatically detects your Next.js setup
- Detects App Router vs Pages Router
- Finds existing TypeScript configuration
- Checks for existing upload implementations
- Validates project structure
Provider Setup
Configures your chosen cloud storage provider
- AWS S3, Cloudflare R2, DigitalOcean Spaces
- Google Cloud Storage, MinIO
- Automatic bucket creation
- CORS configuration
Code Generation
Creates production-ready code
- Type-safe API routes
- Upload client configuration
- Example components
- Environment variable templates
Interactive Setup
Guided configuration with smart defaults
The CLI walks you through each step, asking only what's necessary for your specific setup.
CLI Commands
init
- Initialize Setup
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
# Skip provider selection, use AWS S3
npx @pushduck/cli@latest init --provider aws
# Use custom API route path
npx @pushduck/cli@latest init --api-path /api/files
# Generate only components, skip bucket creation
npx @pushduck/cli@latest init --skip-bucket --skip-examples
add
- Add Upload Route
npx @pushduck/cli@latest add
Add new upload routes to existing configuration:
# Interactive route builder
npx @pushduck/cli@latest add
# Example output:
# ✨ Added imageUpload route for profile pictures
# ✨ Added documentUpload route for file attachments
# ✨ Updated router types
test
- Test Configuration
npx @pushduck/cli@latest test [options]
Options:
--verbose
- Show detailed test output
Validates your current setup:
npx @pushduck/cli@latest test
# Example output:
# ✅ Environment variables configured
# ✅ S3 bucket accessible
# ✅ CORS configuration valid
# ✅ API routes responding
# ✅ Types generated correctly
Interactive Setup Walkthrough
Step 1: Project Detection
🔍 Detecting your project...
✓ Next.js App Router detected
✓ TypeScript configuration found
✓ Package manager: pnpm detected
✓ No existing upload configuration
✓ Project structure validated
Step 2: Provider Selection
? Which cloud storage provider would you like to use?
❯ Cloudflare R2 (recommended)
AWS S3 (classic, widely supported)
DigitalOcean Spaces (simple, affordable)
Google Cloud Storage (enterprise-grade)
MinIO (self-hosted, open source)
Custom S3-compatible endpoint
Step 3: Credential Setup
🔧 Setting up Cloudflare R2...
🔍 Checking for existing credentials...
✓ Found CLOUDFLARE_R2_ACCESS_KEY_ID
✓ Found CLOUDFLARE_R2_SECRET_ACCESS_KEY
✓ Found CLOUDFLARE_R2_ACCOUNT_ID
⚠ CLOUDFLARE_R2_BUCKET_NAME not found
? Enter your R2 bucket name: my-app-uploads
? Create bucket automatically? Yes
Step 4: API Configuration
? Where should we create the upload API?
❯ app/api/upload/route.ts (recommended)
app/api/s3-upload/route.ts (classic)
Custom path
? Generate example upload page?
❯ Yes, create app/upload/page.tsx with full example
Yes, just add components to components/ui/
No, I'll build my own
Step 5: File Generation
🛠️ Generating files...
✨ Created files:
├── app/api/upload/route.ts
├── app/upload/page.tsx
├── components/ui/upload-button.tsx
├── components/ui/upload-dropzone.tsx
├── lib/upload-client.ts
└── .env.example
📦 Installing dependencies...
✓ pushduck
✓ @aws-sdk/client-s3
✓ react-dropzone
🎉 Setup complete! Your uploads are ready.
Generated Project Structure
After running the CLI, your project will have:
Generated API Route
// No longer needed - use uploadRouter.handlers directly
import { s3 } from '@/lib/upload'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
const s3Router = s3.createRouter({
// Image uploads for profile pictures
imageUpload: s3.image()
.max("5MB")
.count(1)
.formats(["jpeg", "png", "webp"])
.middleware(async ({ req, metadata }) => {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
throw new Error("Authentication required")
}
return {
...metadata,
userId: session.user.id,
folder: `uploads/${session.user.id}`
}
}),
// Document uploads
documentUpload: s3.file()
.max("10MB")
.count(5)
.types(["application/pdf", "text/plain", "application/msword"])
.middleware(async ({ req, metadata }) => {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
throw new Error("Authentication required")
}
return {
...metadata,
userId: session.user.id,
folder: `documents/${session.user.id}`
}
})
})
export type AppRouter = typeof s3Router
export const { GET, POST } = s3Router.handlers
Generated Upload Client
import { createUploadClient } from 'pushduck/client'
import type { AppRouter } from '@/app/api/upload/route'
export const upload = createUploadClient<AppRouter>({
endpoint: '/api/upload'
})
Generated Example Page
import { UploadButton } from '@/components/ui/upload-button'
import { UploadDropzone } from '@/components/ui/upload-dropzone'
export default function UploadPage() {
return (
<div className="container mx-auto py-8">
<h1 className="text-3xl font-bold mb-8">File Upload Demo</h1>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h2 className="text-xl font-semibold mb-4">Profile Picture</h2>
<UploadButton uploadType="imageUpload" />
</div>
<div>
<h2 className="text-xl font-semibold mb-4">Documents</h2>
<UploadDropzone uploadType="documentUpload" />
</div>
</div>
</div>
)
}
Environment Variables
The CLI automatically creates .env.example
and prompts for missing values:
# Cloudflare R2 Configuration (Recommended)
CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_here
CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_key_here
CLOUDFLARE_R2_ACCOUNT_ID=your_account_id_here
CLOUDFLARE_R2_BUCKET_NAME=your-bucket-name
# Alternative: AWS S3 Configuration
# AWS_ACCESS_KEY_ID=your_access_key_here
# AWS_SECRET_ACCESS_KEY=your_secret_key_here
# AWS_REGION=us-east-1
# AWS_S3_BUCKET_NAME=your-bucket-name
# Next.js Configuration
NEXTAUTH_SECRET=your_nextauth_secret_here
NEXTAUTH_URL=http://localhost:3000
# Optional: Custom S3 endpoint (for MinIO, etc.)
# S3_ENDPOINT=https://your-custom-endpoint.com
Provider-Specific Setup
npx @pushduck/cli@latest init --provider cloudflare-r2
What gets configured:
- Cloudflare R2 S3-compatible endpoints
- Global edge network optimization
- Zero egress fee configuration
- CORS settings for web uploads
npx @pushduck/cli@latest init --provider aws
What gets configured:
- AWS S3 regional endpoints
- IAM permissions and policies
- Bucket lifecycle management
- CloudFront CDN integration (optional)
npx @pushduck/cli@latest init --provider digitalocean
Required Environment Variables:
AWS_ACCESS_KEY_ID
(DO Spaces key)AWS_SECRET_ACCESS_KEY
(DO Spaces secret)AWS_REGION
(DO region)AWS_S3_BUCKET_NAME
S3_ENDPOINT
(DO Spaces endpoint)
What the CLI does:
- Configures DigitalOcean Spaces endpoints
- Sets up CDN configuration
- Validates access permissions
- Configures CORS policies
npx @pushduck/cli@latest init --provider minio
Required Environment Variables:
AWS_ACCESS_KEY_ID
(MinIO access key)AWS_SECRET_ACCESS_KEY
(MinIO secret key)AWS_REGION=us-east-1
AWS_S3_BUCKET_NAME
S3_ENDPOINT
(MinIO server URL)
What the CLI does:
- Configures self-hosted MinIO endpoints
- Sets up bucket policies
- Validates server connectivity
- Configures development-friendly settings
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 init
Permission 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:$PATH
Existing Configuration
# Force overwrite existing configuration
npx @pushduck/cli@latest init --force
# Or backup and regenerate
cp app/api/upload/route.ts app/api/upload/route.ts.backup
npx @pushduck/cli@latest init
Bucket 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 test
Advanced Usage
Custom Templates
# Use custom file templates
npx @pushduck/cli@latest init --template enterprise
# Available templates:
# - default: Basic setup with examples
# - minimal: Just API routes, no examples
# - enterprise: Full security and monitoring
# - ecommerce: Product images and documents
Monorepo 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/web
CI/CD Integration
# Non-interactive mode for CI/CD
npx @pushduck/cli@latest init \
--provider aws \
--skip-examples \
--api-path /api/upload \
--no-interactive
Complete CLI Reference: This guide covers all CLI commands, options, and use cases. For a quick start, see our Getting Started guide.