LogoMkSaaS Docs
LogoMkSaaS Docs
HomepageIntroductionCodebaseVideo TutorialsGetting Started: Install and Run LocallyEnvironment Setup
Configuration

Integrations

DatabaseAuthenticationEmailNewsletterStorage
Payment
AIAnalyticsNotificationCaptchaChatboxAffiliates

Customization

MetadataFontsThemesImagesSaaS Internationalization with next-intlBlogDocsComponentsCustom PagesLanding PageUser ManagementAPI Key Management

Codebase

IDE SetupProject StructureFormatting & LintingAutomated TestingUpdating the Codebase
X (Twitter)

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.

Setup

Create Cloudflare R2 Bucket (Recommended)

  1. Create a Cloudflare account at cloudflare.com
  2. 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

Enable Public Access

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 API Token

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 Environment Variables

Set the following environment variables:

.env
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.

S3-Compatible Alternatives

MkSaaS is compatible with any S3-compatible storage service, including:

  • Amazon S3 - Amazon's storage service
  • Backblaze B2 - Very cost-effective option
  • Google Cloud Storage - High performance with Google infrastructure
  • Digital Ocean Spaces - Simple pricing and integrated with DO infrastructure

If you are setting up the environment, now you can go back to the Environment Setup guide and continue. The rest of this guide can be read later.

Environment Setup

Set up environment variables


Usage

Basic File Operations

MkSaaS provides simple utilities for common file operations:

import { uploadFile, deleteFile } 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);

Browser-Side Uploads

For uploading files directly from the browser, use the uploadFileFromBrowser function:

'use client';

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);
  }
}

This helper sends multipart/form-data to the protected POST /api/storage/upload route. The user must be signed in. The built-in route accepts JPEG, PNG, and WebP files up to 4 MB; change the route and MAX_FILE_SIZE together if your product needs different limits. Uploads are proxied through the server because the bundled s3mini provider does not issue presigned upload URLs.

Extending New Storage Providers

MkSaaS supports extending with new storage service providers:

  1. Create a new file in the src/storage/provider directory

  2. Implement the StorageProvider interface:

src/storage/provider/custom-provider.ts
import {
  type StorageProvider,
  type UploadFileParams,
  type 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
  }
}
  1. Add the provider name to StorageConfig['provider'] in src/types/index.d.ts, then register its lazy factory in index.ts:
src/storage/index.ts
import { CustomStorageProvider } from './provider/custom-provider';

const providerRegistry: Partial<
  Record<StorageProviderName, StorageProviderFactory>
> = {
  s3: () => new S3Provider(),
  custom: () => new CustomStorageProvider(),
};

Video Tutorial

Next Steps

Payment

Configure payment system

Authentication

Configure user authentication

Database

Configure database

Environment Setup

Configure environment variables

Newsletter

Learn how to set up and use Resend or Beehiiv for newsletter management

Payment

Learn how to set up and use payment providers in MkSaaS

Table of Contents

SetupCreate Cloudflare R2 Bucket (Recommended)Enable Public AccessCreate API TokenSet Environment VariablesS3-Compatible AlternativesUsageBasic File OperationsBrowser-Side UploadsExtending New Storage ProvidersVideo TutorialNext Steps