Skip to main content

Overview

This guide covers two installation scenarios:
  1. Development setup — For contributing to OpenCut or running it locally
  2. Self-hosting with Docker — For running your own production instance

Development setup

Set up a local development environment

Self-hosting

Deploy your own production instance

Development setup

Prerequisites

Before you begin, ensure you have:

Bun

Required — JavaScript runtime (v1.2.18+)Install Bun

Docker

Optional — For database and RedisInstall Docker

Node.js

Alternative — v18 or later if not using BunInstall Node.js

Git

Required — For cloning the repositoryInstall Git
Docker is optional but recommended. If you only want to work on frontend features, you can skip the Docker setup.

Step 1: Clone the repository

Fork and clone the OpenCut repository:
# Clone your fork (replace YOUR-USERNAME with your GitHub username)
git clone https://github.com/YOUR-USERNAME/OpenCut.git
cd OpenCut
Contributing? Make sure to fork the repository first so you can submit pull requests later.

Step 2: Environment configuration

Copy the example environment file and configure it:
cp apps/web/.env.example apps/web/.env.local
Edit apps/web/.env.local with your configuration:
apps/web/.env.local
# Node environment
NODE_ENV=development

# Public URLs
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_MARBLE_API_URL=https://api.marblecms.com

# Database (matches docker-compose.yml)
DATABASE_URL="postgresql://opencut:opencut@localhost:5432/opencut"

# Authentication
BETTER_AUTH_SECRET=your_better_auth_secret

# Redis (matches docker-compose.yml)
UPSTASH_REDIS_REST_URL=http://localhost:8079
UPSTASH_REDIS_REST_TOKEN=example_token

# Optional: Marble CMS for blog
MARBLE_WORKSPACE_KEY=your_workspace_key_here

# Optional: Freesound audio library
FREESOUND_CLIENT_ID=your_client_id_here
FREESOUND_API_KEY=your_api_key_here

# Optional: Auto-captions (Cloudflare R2 + Modal)
CLOUDFLARE_ACCOUNT_ID=your_account_id_here
R2_ACCESS_KEY_ID=your_access_key_here
R2_SECRET_ACCESS_KEY=your_secret_key_here
R2_BUCKET_NAME=opencut-transcription
MODAL_TRANSCRIPTION_URL=your_modal_url_here
You need a secure secret for authentication. Generate one using any of these methods:
openssl rand -base64 32
Or use an online generator: generate-secret.vercel.app/32
The default values in .env.example match the Docker Compose configuration and should work out of the box for local development.

Step 3: Start services

If using Docker, start the database and Redis services:
# Start only the required services for development
docker compose up -d db redis serverless-redis-http
This starts:
  • PostgreSQL on localhost:5432
  • Redis on localhost:6379
  • Serverless Redis HTTP on localhost:8079
Check if services are running:
docker compose ps
View logs:
# All services
docker compose logs -f

# Specific service
docker compose logs -f db
Stop services:
docker compose down

Step 4: Install dependencies

Install project dependencies:
bun install
If you see Unsupported URL Type "workspace:*" with npm, upgrade to npm v9+ or use Bun/pnpm instead.

Step 5: Database setup

Run database migrations (only if using Docker):
cd apps/web
bun run db:migrate
cd ../..
Available database commands:
# Generate migration files
bun run db:generate

# Run migrations
bun run db:migrate

# Push schema to local database
bun run db:push:local

# Push schema to production database
bun run db:push:prod

Step 6: Start development server

Start the Next.js development server:
bun dev:web
The application will be available at http://localhost:3000.
Success! Your development environment is ready. Changes to the code will automatically reload thanks to hot module replacement.

Self-hosting with Docker

Run your own production instance of OpenCut using Docker Compose.

Prerequisites

  • Docker and Docker Compose
  • A server or VPS with at least 2GB RAM
  • (Optional) A domain name for public access

Quick deployment

The simplest way to run OpenCut in production:
1

Clone the repository

git clone https://github.com/OpenCut-app/OpenCut.git
cd OpenCut
2

Configure environment

Create a .env file in the project root for production configuration:
.env
# Generate a secure secret
BETTER_AUTH_SECRET=your-production-secret-here

# Optional: Freesound integration
FREESOUND_CLIENT_ID=your_client_id
FREESOUND_API_KEY=your_api_key

# Optional: Marble CMS blog
MARBLE_WORKSPACE_KEY=your_workspace_key

# Optional: Auto-captions
CLOUDFLARE_ACCOUNT_ID=your_account_id
R2_ACCESS_KEY_ID=your_r2_access_key
R2_SECRET_ACCESS_KEY=your_r2_secret
R2_BUCKET_NAME=opencut-transcription
MODAL_TRANSCRIPTION_URL=your_modal_url
Never commit your .env file! It contains sensitive credentials. The file is already in .gitignore.
3

Start all services

docker compose up -d
This builds and starts:
  • OpenCut web application
  • PostgreSQL database
  • Redis cache
  • Serverless Redis HTTP adapter
The app will be available at http://localhost:3100.

Docker Compose configuration

The docker-compose.yml includes all necessary services:
docker-compose.yml
services:
  # PostgreSQL database
  db:
    image: postgres:17
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: opencut
      POSTGRES_PASSWORD: opencut
      POSTGRES_DB: opencut
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # Redis cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  # Serverless Redis HTTP adapter
  serverless-redis-http:
    image: hiett/serverless-redis-http:latest
    ports:
      - "8079:80"
    environment:
      SRH_TOKEN: example_token
      SRH_CONNECTION_STRING: "redis://redis:6379"

  # OpenCut web application
  web:
    build:
      context: .
      dockerfile: ./apps/web/Dockerfile
    ports:
      - "3100:3000"
    environment:
      NODE_ENV: production
      DATABASE_URL: postgresql://opencut:opencut@db:5432/opencut
      # ... other environment variables
To change the external port, edit the ports mapping in docker-compose.yml:
ports:
  - "8080:3000"  # Change 8080 to your desired port

Production considerations

For production, use a reverse proxy like Nginx or Caddy:Nginx example:
server {
    listen 80;
    server_name opencut.yourdomain.com;

    location / {
        proxy_pass http://localhost:3100;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
Caddy example:
opencut.yourdomain.com {
    reverse_proxy localhost:3100
}
Use Let’s Encrypt for free SSL certificates:
# With Caddy (automatic)
caddy run

# With Certbot + Nginx
sudo certbot --nginx -d opencut.yourdomain.com
Update NEXT_PUBLIC_SITE_URL in your environment:
NEXT_PUBLIC_SITE_URL=https://opencut.yourdomain.com
Set up automated PostgreSQL backups:
# Manual backup
docker compose exec db pg_dump -U opencut opencut > backup.sql

# Restore from backup
docker compose exec -T db psql -U opencut opencut < backup.sql
Consider using automated backup solutions like:
View logs:
# All services
docker compose logs -f

# Specific service
docker compose logs -f web

# Last 100 lines
docker compose logs --tail=100
Consider adding monitoring:
Set resource limits in docker-compose.yml:
services:
  web:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

Project structure

Understanding the codebase structure:
OpenCut/
├── apps/
│   └── web/                 # Main Next.js application
│       ├── src/
│       │   ├── app/         # Next.js app router pages
│       │   ├── components/  # React components
│       │   ├── core/        # Editor core system
│       │   ├── hooks/       # Custom React hooks
│       │   ├── lib/         # Business logic and utilities
│       │   ├── services/    # External services (renderer, etc.)
│       │   ├── stores/      # Zustand state management
│       │   └── types/       # TypeScript type definitions
│       ├── public/          # Static assets
│       ├── Dockerfile       # Production Docker image
│       └── package.json     # Web app dependencies
├── packages/                # Shared packages
│   ├── env/                 # Environment configuration
│   └── ui/                  # Shared UI components
├── docker-compose.yml       # Docker services configuration
├── turbo.json              # Turborepo configuration
└── package.json            # Root workspace configuration
See AGENTS.md in the repository for detailed architecture documentation.

Troubleshooting

If ports are already in use:
# Check what's using a port (macOS/Linux)
lsof -i :3000

# Check what's using a port (Windows)
netstat -ano | findstr :3000

# Kill process by PID
kill -9 <PID>          # macOS/Linux
taskkill /PID <PID> /F # Windows
Common Docker problems:
# Restart Docker Desktop
# macOS: Restart from menu bar icon
# Windows: Restart from system tray

# Clear Docker cache
docker system prune -a

# Rebuild containers
docker compose down -v
docker compose build --no-cache
docker compose up -d
If the build fails:
# Clear bun cache
rm -rf node_modules
rm -rf apps/web/node_modules
bun install

# Clear Next.js cache
rm -rf apps/web/.next
bun build:web
Verify database connectivity:
# Check if database is running
docker compose ps db

# Test connection
docker compose exec db psql -U opencut -d opencut -c "SELECT 1;"

# Check logs
docker compose logs db

Next steps

Contributing

Learn how to contribute to OpenCut

Architecture

Understand the editor architecture

Core concepts

Learn about the editor core system

API reference

Explore the API documentation

Build docs developers (and LLMs) love