Demo
General

Storage

Manage file uploads and storage with Cloudflare R2 or any S3-compatible provider.

The Pro Next.js Drizzle starter kit includes a robust storage service pre-configured for Cloudflare R2, but compatible with any S3-compatible service (AWS S3, DigitalOcean Spaces, MinIO, etc.).

Overview

The storage service provides:

  • Signed URLs for secure uploads and downloads
  • Path validation to prevent security issues
  • S3-compatible API supporting multiple providers
  • Direct client uploads to reduce server load

Supported Providers

  • Cloudflare R2
  • AWS S3
  • DigitalOcean Spaces
  • MinIO
  • Any S3-compatible service

Storage Functions

The storage functions in lib/storage provide methods for generating signed URLs for both uploads and downloads.

Getting a Signed Upload URL

Generate a short-lived URL on the server that allows the client to upload a file directly to the bucket.

lib/actions/upload.ts
import { storageConfig } from '@/config/storage.config';
import { getSignedUploadUrl } from '@/lib/storage';

const signedUrl = await getSignedUploadUrl(
  'avatars/user-1.png',
  storageConfig.bucketNames.images
);

Getting a Signed Download URL

Generate a signed URL for downloading files:

lib/actions/download.ts
import { storageConfig } from '@/config/storage.config';
import { getSignedUrl } from '@/lib/storage';

const signedUrl = await getSignedUrl(
  'avatars/user-1.png',
  storageConfig.bucketNames.images,
  3600 // Expires in 1 hour (in seconds)
);

UI Components

We provide ready-to-use components for common storage tasks.

Avatar Upload

The UserAvatarUpload component handles image selection, cropping, and direct upload to R2.

components/user/user-avatar-upload.tsx
import { UserAvatarUpload } from '@/components/user/user-avatar-upload';

export function ProfileSettings() {
  return <UserAvatarUpload />;
}

Displaying Images

The useStorage hook converts storage paths into accessible URLs automatically.

components/user/user-avatar.tsx
import { useStorage } from '@/hooks/use-storage';

function MyAvatar({ path }: { path: string }) {
  const url = useStorage(path);
  return (
    <img
      src={url}
      alt="Avatar"
    />
  );
}

Security

  • Signed URLs: All uploads and downloads use time-limited signed URLs.
  • Path Validation: All file paths are sanitized to prevent traversal attacks.
  • CORS: Ensure your R2/S3 bucket is configured with the correct CORS policy to allow uploads from your domain.
  • Access Control: Files are not publicly accessible by default - access is controlled through signed URLs.