R2 File Management
TanStack Ship R2 file management system for Cloudflare object storage, file upload and management, signed URL generation, and audit logging.
Overview
The R2 file management system in TanStack Ship provides a complete, production-ready solution for handling file uploads and asset storage using Cloudflare R2 serverless object storage. From marketing images and blog media to downloadable resources and user-uploaded content, the system manages the entire file lifecycle — upload, storage, access control, and deletion — with full audit trail capabilities.
As part of the platform, the R2 file management module integrates with the Blog CMS for media storage, the admin dashboard for file management, and URL generation APIs for secure asset delivery. The system supports both public and signed URL access patterns, making it suitable for a wide range of content delivery scenarios.
Design Flow
The R2 file management system orchestrates the complete file lifecycle from upload through storage to access, with audit logging at every stage:
Core Capabilities
File Upload System
Files can be uploaded through multiple channels, each with consistent audit logging:
- Admin Interface — Upload via the R2 management page with drag-and-drop and bulk upload capabilities
- API Endpoint — Programmatic upload with multipart form data, supporting authentication and rate limiting
- Direct Upload — Server-to-server file transfer for backend workflows
Each upload is recorded with complete metadata — file name, size, content type, uploading user, and timestamps — providing a reliable audit trail for billing, compliance, and troubleshooting.
File Management Interface
The admin interface provides comprehensive file management capabilities:
- File Browser — Browse all uploaded files with thumbnail previews for images and document icons for other formats
- Search & Filter — Find files by name, date range, uploader, or content type
- File Preview — View images, PDFs, and text files directly in the browser
- Bulk Operations — Select and delete multiple files with confirmation safeguards
- File Details — Inspect metadata including storage location, access URL, upload date, and file hash
URL Generation and Access Control
The system supports multiple URL generation strategies:
- Public URLs — Direct R2 public bucket URLs for serving images, CSS, and public assets. Ideal for marketing content and blog media.
- Signed URLs — Time-limited, pre-signed URLs for private file access. Expiration is configurable per request, ensuring sensitive files remain protected while enabling temporary sharing.
Example — Signed URL response:
{
"signedUrl": "https://pub-xxx.r2.dev/file.pdf?X-Amz-Algorithm=...&X-Amz-Expires=3600",
"expiresIn": 3600,
"key": "uploads/2025/06/report.pdf"
}
**Example — Fetching a signed URL in React:**
```tsx
import { useQuery } from '@tanstack/react-query'
function SecureDownload({ fileKey }: { fileKey: string }) {
const { data, isLoading } = useQuery({
queryKey: ['signed-url', fileKey],
queryFn: async () => {
const res = await fetch(`/api/r2/sign/${fileKey}`)
if (!res.ok) throw new Error('Failed to get signed URL')
return res.json() as Promise<{ signedUrl: string; expiresIn: number }>
},
})
if (isLoading) return <div>Preparing download...</div>
return (
<a href={data?.signedUrl} download>
Download File
</a>
)
}
Design Philosophy
Audit-First Operations
Every file operation — upload, access, deletion — is recorded in the audit log with complete metadata: file name, size, content type, user attribution, and timestamps. This audit-first philosophy means the system provides an immutable record of all file lifecycle events, supporting compliance requirements, billing verification, and operational troubleshooting. The audit table is the source of truth for all file-related activity.
Dual Access Model
The system supports both public and signed URL access patterns for different use cases. Public URLs serve static assets (images, CSS, downloadable resources) with zero overhead, while signed URLs provide time-limited access to private files with configurable expiration. This dual model gives platform operators fine-grained control over asset security — sensitive documents require authentication and expire automatically, while marketing assets are delivered globally via R2's edge network.
Serverless by Default
By building on Cloudflare R2, the file management system inherits serverless benefits: zero egress fees, automatic global distribution via edge caching, and no infrastructure management. Unlike traditional AWS S3 setups that charge per-gigabyte for data transfers, R2 eliminates egress fees entirely while maintaining 100% S3 API compatibility — making it a cost-effective alternative for high-traffic applications, media delivery, and multi-region workloads. Files are stored across Cloudflare's global network and served from the edge node nearest to each user. This architecture eliminates the operational burden of managing file servers and CDN configurations while providing enterprise-grade performance and reliability.
Best Practices
File Size and Type Validation
Configure file size limits and allowed MIME types. Set your desired maximum file size (50MB by default) and restrict upload types to your application's needs to prevent storage exhaustion and block malicious uploads.
Signed URL Expiration Management
Choose expiration times based on your use case: use short durations (5-15 minutes) for one-time downloads of sensitive documents, and longer durations (1-24 hours) for batch processing workflows.
Storage Organization Strategy
Adopt a logical key prefix strategy for organizing files:
uploads/{year}/{month}/{uuid}-{name}for user uploadsblog/{year}/{slug}/{name}for blog mediamarketing/{campaign-name}/{name}for marketing assets
This naming convention keeps storage organized, enables efficient listing by prefix, and prevents key collisions.
Regular Audit Review
Periodically review the upload audit table to identify orphaned or unused files. Consider implementing a lifecycle policy that flags files older than a configurable threshold for review.
Frequently Asked Questions
What file types can I upload? Common file types are accepted by default: images (JPEG, PNG, WebP, GIF, SVG), documents (PDF, DOCX, TXT), and media files (MP4, MP3). Allowed MIME types can be extended through configuration.
How do I generate a signed URL for a private file? Request a signed URL through the API with authentication headers. The response includes a pre-signed URL valid for 1 hour by default, with customizable expiration.
Can I organize files into folders?
The system uses a flat key-value storage model, but folders can be simulated by using prefix-based key naming (e.g., blog/2024/my-post/image.jpg).
Is there a limit on how many files I can store? Cloudflare R2 has no limit on the number of objects you can store. Be aware of your account's storage quota and set appropriate size limits.
How does the system handle duplicate file names? Each uploaded file receives a unique key, typically incorporating a UUID or timestamp prefix to prevent collisions. The original filename is preserved in metadata for display.
Can I delete files in bulk? Yes. The admin interface supports selecting multiple files and deleting them in a single operation.
Configuration
Configure R2 by setting these environment variables:
R2_BUCKET_NAME=your-bucket
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_PUBLIC_URL=https://pub-xxx.r2.dev
R2_MAX_FILE_SIZE=52428800
The R2 bucket binding must also be configured in the project's wrangler configuration. For local development, a mock mode simulates R2 storage without requiring actual bucket configuration.
Integration Points
The R2 file management system integrates with these platform modules:
- Blog CMS — Blog post images, cover photos, and media assets are stored and served from R2
- Admin Dashboard — Full file management interface accessible from the admin panel
- Marketing Content — Marketing page images, banners, and downloadable resources are distributed through public URLs
- Email Marketing — Email campaign assets and inline images are hosted on R2
- User Profiles — Avatar and profile image uploads are stored in per-user key prefixes