Storage Learn how to set up and use cloud storage for file uploads and media handling
MkSaaS uses Amazon S3 and compatible services like Cloudflare R2 for file storage and media handling, providing a reliable and scalable solution for storing images and other media files.
To set up storage in MkSaaS, follow these steps to configure the necessary environment variables:
Create a Cloudflare account at cloudflare.com
Create a new R2 bucket:
Pick a globally unique bucket name (e.g., your-project-name)
Select a region close to your target audience
Set other options according to your needs
Allow public access to the bucket:
Settings > Public Development URL, click Enable
Save the public access URL as STORAGE_PUBLIC_URL
Set custom domains for public access to the bucket (recommended to use custom domains for security)
Create a new API Token:
Storage & databases > R2 object storage > API Tokens > Manage, click Create User API Token
Set permissions to Object Read & Write to the bucket
Create the API Token, get the Access Key ID and Secret Access Key
Set the following environment variables: STORAGE_REGION = YOUR-REGION-OR-AUTO
STORAGE_BUCKET_NAME = YOUR-BUCKET-NAME
STORAGE_ACCESS_KEY_ID = YOUR-ACCESS-KEY
STORAGE_SECRET_ACCESS_KEY = YOUR-SECRET-KEY
STORAGE_ENDPOINT = https://xxx.r2.cloudflarestorage.com
STORAGE_PUBLIC_URL = https://your-custom-domain.com
Set storage provider to s3 because Cloudflare R2 is S3-compatible.
MkSaaS is compatible with any S3-compatible storage service, including:
The storage system in MkSaaS is designed with the following components:
This modular structure makes it easy to extend the storage system with new providers and functionality.
Direct file upload and management for server-side operations
Browser-side file uploading with size-based optimization
Support for Amazon S3 and compatible storage services (e.g. Cloudflare R2)
Folder organization for file management
Automatic file path generation and file naming
Configurable storage region and bucket settings
MkSaaS provides simple utilities for common file operations:
import { uploadFile, deleteFile }
For uploading files directly from the browser, use the uploadFileFromBrowser function:
Below is an example of using the storage system with a form component:
MkSaaS makes it easy to extend the storage system with new storage service providers:
Create a new file in the src/storage/provider directory as a custom storage service provider
Implement the StorageProvider interface
src/storage/provider/custom-provider.ts
Update the storage service provider selection in index.ts:
import { CustomStorageProvider }
File Organization : Use folders to organize files by type or purpose (e.g., uploads/images, documents/contracts)
File Size Limits : Set reasonable file size limits to prevent abuse
File Type Validation : Validate file types on both client and server sides for security
Now that you understand how to work with file storage in MkSaaS, explore these related topics:
from
'@/storage'
;
// Upload a file to storage
const { url , key } = await uploadFile (
fileBuffer,
'original-filename.jpg' ,
'image/jpeg' ,
'uploads/images'
);
// Delete a file from storage
await deleteFile (key);
import { uploadFileFromBrowser } from '@/storage/client' ;
// In your React component
async function handleFileUpload ( event ) {
const file = event.target.files[ 0 ];
try {
const { url , key } = await uploadFileFromBrowser (file, 'uploads/images' );
console. log ( 'File uploaded:' , url);
} catch (error) {
console. error ( 'Upload failed:' , error);
}
}
import { useState } from 'react' ;
import { uploadFileFromBrowser } from '@/storage/client' ;
import { Button } from '@/components/ui/button' ;
export function ImageUploader () {
const [ isUploading , setIsUploading ] = useState ( false );
const [ imageUrl , setImageUrl ] = useState < string | null >( null );
async function handleFileChange ( event : React . ChangeEvent < HTMLInputElement >) {
const file = event.target.files?.[ 0 ];
if ( ! file) return ;
try {
setIsUploading ( true );
const { url } = await uploadFileFromBrowser (file, 'profile-images' );
setImageUrl (url);
} catch (error) {
console. error ( 'Upload failed:' , error);
} finally {
setIsUploading ( false );
}
}
return (
< div className = "space-y-4" >
< div className = "flex items-center gap-4" >
< Button
variant = "outline"
onClick = {() => document. getElementById ( 'file-upload' )?. click ()}
disabled = {isUploading}
>
{isUploading ? 'Uploading...' : 'Upload Image' }
</ Button >
< input
id = "file-upload"
type = "file"
accept = "image/*"
className = "hidden"
onChange = {handleFileChange}
/>
</ div >
{imageUrl && (
< div className = "w-32 h-32 relative" >
< img
src = {imageUrl}
alt = "Uploaded image"
className = "object-cover w-full h-full rounded-md"
/>
</ div >
)}
</ div >
);
}
{
PresignedUploadUrlParams,
StorageProvider,
UploadFileParams,
UploadFileResult
} from '@/storage/types' ;
export class CustomStorageProvider implements StorageProvider {
constructor () {
// Initialize your storage service provider
}
public getProviderName () : string {
return 'CustomProvider' ;
}
async uploadFile ( params : UploadFileParams ) : Promise < UploadFileResult > {
// Implementation for uploading a file
return { url: 'https://example.com/file.jpg' , key: 'file.jpg' };
}
async deleteFile ( key : string ) : Promise < void > {
// Implementation for deleting a file
}
}
from
'./provider/custom-provider'
;
export const initializeStorageProvider = () : StorageProvider => {
if ( ! storageProvider) {
if (websiteConfig.storage.provider === 's3' ) {
storageProvider = new S3Provider ();
} else if (websiteConfig.storage.provider === 'custom' ) {
storageProvider = new CustomStorageProvider ();
} else {
throw new Error (
`Unsupported storage provider: ${ websiteConfig . storage . provider }`
);
}
}
return storageProvider;
};
Storage | MkSaaS - Make Your AI SaaS Product in a Weekend