Overview
Configure and use S3-backed file uploads with presigned URLs.
AI Skill for storage
/storage in your Copilot / Cursor or other chat to use skill with the provided context./storage Add file upload for [describe entity/form].
Use cases: What to store in S3
Instead of saving files directly to your application server (which is anti-pattern in modern scalable apps), GoLiveKit is configured to upload files directly into an S3-compatible service. Common use cases include:
- User Avatars: Profile pictures and company logos.
- Documents & Attachments: PDFs, CSVs, or other user-submitted files.
- Media: Images hosted for blog posts, e-commerce products, or user generated content.
Direct-to-S3 Uploads
GoLiveKit uploads files straight from the browser to the S3 bucket using presigned URLs. This offloads entirely the upload bandwidth from your Node.js application server.
Required Environment Variables
You need to set up credentials for any S3-compatible object storage provider.
S3_REGION=auto
S3_BUCKET=your-bucket-name
S3_ACCESS_KEY_ID=your-copied-access-key-id
S3_SECRET_ACCESS_KEY=your-copied-secret-access-key
S3_ENDPOINT=https://your-account-id.r2.cloudflarestorage.comS3_REGION=us-east-1
S3_BUCKET=your-bucket
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
# S3_ENDPOINT is not required for AWS S3Cloudflare R2 Setup Guide
Learn how to configure Cloudflare R2 object storage with zero egress fees.
AWS S3 Setup Guide
Step-by-step guide to configuring AWS S3 for direct file uploads.
App Configuration
Common storage defaults are defined in src/config/app.ts under APP_CONFIG.files.storage. These are the global safety limits:
keyPrefix: The folder path prefix where files are stored inside your bucket.presignedUrlExpiresInSeconds: How long the upload URL remains valid.maxFileSizeBytes: The maximum allowed size for uploaded files globally.maxFilesCount: The overall file limit per upload batch.acceptedTypes: Global accept rules (likeimage/*,application/pdf).
Note: Per-field upload settings from specific forms can restrict uploads further, but can never exceed these global maximum thresholds.
The Upload Flow (API Endpoints)
The application uses a 3-step direct-to-S3 approach:
Request presigned URL
The client hits the oRPC endpoint (POST /api/v1/files/create-presigned-upload-url) to get a secure upload target.
Upload directly
The client uploads file bytes straight to S3 via PUT request without touching your server.
Finalize
The client calls POST /api/v1/files/finalize-upload to register the new file record in your postgres database for later use.
Note: If the upload request is authenticated, the userId is automatically attached to the resulting file metadata.
UI Integration
To implement file uploading in your React views or forms, you can use the built-in <FileDropzone /> component. This handles the entire S3 orchestration behind the scenes.
import { useState } from 'react';
import { FileDropzone } from '@/features/common/files/components/file-dropzone';
import type { UploadedFile } from '@/features/common/files/model/files.schema';
export function AvatarUploader() {
const [files, setFiles] = useState<UploadedFile[]>([]);
return (
<div className="max-w-md">
<FileDropzone
value={files}
onChange={setFiles}
view="image" // Use "file" for general attachments or "image" for image previews
maxFilesCount={1}
maxFileSizeBytes={5_000_000} // Override locally (up to max global limit)
acceptedTypes={['image/jpeg', 'image/png']}
/>
{files.length > 0 && (
<p className="mt-2 text-sm text-muted-foreground">
Uploaded File ID: {files[0].id}
</p>
)}
</div>
);
}