Storage
Understand the image storage integration that ships with the Pro Next.js Prisma starter kit.
The starter kit includes an S3-compatible image storage integration for user avatars and organization logos. It is configured for Cloudflare R2 and can be adapted to another provider that supports the S3 API.
Security boundary
The upload signer requires an authenticated user. The download route does not.
The shipped /storage/[...path] route will generate a one-hour
signed download URL for anyone who knows a valid image key. A signed URL
limits how long storage credentials can be used, but it does not prove file
ownership or organization membership.
Setup
Upload Files
Access Files
What ships
lib/storage/s3.tscreates an S3 client and presignsPutObjectandGetObjectcommands.trpc/routers/storage/index.tsexposes an authenticatedstorage.signedUploadUrlmutation for the configured images bucket.app/storage/[...path]/route.tsexposes a public image redirect route.hooks/use-storage.tsxconverts a stored image key into the public route URL.- Avatar and organization logo components crop an image, upload it directly and save its key through Better Auth.
The included flow is intended for display images such as avatars and logos. The generated UUID-based keys make accidental discovery less likely, but an unguessable key is not authorization.
What does not ship
The repositories do not include:
- A
Filemodel or file metadata table - User or organization ownership checks for storage objects
- Private download, listing or deletion procedures
- File quota enforcement, malware scanning or audit logs
- Automatic object deletion when an avatar or logo is removed
- Server-enforced file size or MIME type validation
Add those controls before using the storage integration for invoices, exports, identity documents or other private files. See Access Files for the required design changes.
Environment variables
S3_ACCESS_KEY_ID="your-access-key"
S3_SECRET_ACCESS_KEY="your-secret-key"
S3_ENDPOINT="https://your-s3-endpoint"
S3_REGION="auto"
NEXT_PUBLIC_IMAGES_BUCKET_NAME="your-images-bucket"NEXT_PUBLIC_IMAGES_BUCKET_NAME is public configuration. Keep the access key and secret key server-only.