Self-Hosting

Deploy Schemaful to your own infrastructure.

Requirements

  • Node.js 22+ (or Docker)
  • PostgreSQL 14+ database
  • 512MB RAM minimum (1GB recommended)

Docker Deployment

The easiest way to deploy Schemaful is with Docker.

Docker Compose

docker-compose.yml
version: "3.8"

services:
  schemaful:
    image: schemaful/cms:latest
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/schemaful
      - NODE_ENV=production
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=schemaful
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Run

docker-compose up -d

Access Schemaful at http://localhost:3000

Vercel Deployment

Deploy to Vercel with a managed PostgreSQL database (Neon recommended).

1. Create Neon Database

Sign up at neon.tech and create a new project. Copy the connection string.

2. Deploy to Vercel

# Clone and deploy
npx create-schemaful@latest my-cms
cd my-cms
vercel

3. Add Environment Variables

In Vercel dashboard, add DATABASE_URL with your Neon connection string.

Railway Deployment

Railway provides automatic PostgreSQL provisioning.

# Install Railway CLI
npm install -g @railway/cli

# Login and deploy
railway login
railway init
railway add --plugin postgresql
railway up

Railway automatically sets DATABASE_URL.

Manual Node.js

Deploy on any server with Node.js.

# Clone repository
git clone https://github.com/schemaful/schemaful
cd schemaful

# Install dependencies
pnpm install

# Build
pnpm build

# Set environment variables
export DATABASE_URL="postgresql://..."
export NODE_ENV="production"

# Run migrations
pnpm db:push

# Start server
pnpm start

Environment Variables

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string
NODE_ENVNoEnvironment (production, development)
SESSION_SECRETYes*Secret for session encryption (auto-generated in dev)
ASSET_UPLOAD_URLNoS3-compatible upload endpoint
ASSET_PUBLIC_URLNoCDN URL for serving assets

Database Setup

Schemaful uses Drizzle ORM for database management.

Initialize Tables

# Push schema to database (creates tables)
pnpm db:push

# Or generate and run migrations
pnpm db:generate
pnpm db:migrate

Database Tables

  • cms_locales — Language definitions
  • cms_schemas — Content type definitions
  • cms_fields — Field configurations
  • cms_entries — Content data (JSONB)
  • cms_assets — Media metadata
  • cms_users — User accounts
  • cms_sessions — Active sessions

Asset Storage

By default, assets are stored locally. For production, configure S3-compatible storage:

.env
# Cloudflare R2 (recommended)
ASSET_UPLOAD_URL=https://account.r2.cloudflarestorage.com/bucket
ASSET_PUBLIC_URL=https://cdn.yourdomain.com
R2_ACCESS_KEY_ID=your-key
R2_SECRET_ACCESS_KEY=your-secret

# AWS S3
ASSET_UPLOAD_URL=https://s3.amazonaws.com/bucket
ASSET_PUBLIC_URL=https://bucket.s3.amazonaws.com

Reverse Proxy

Example Nginx configuration:

nginx.conf
server {
    listen 80;
    server_name cms.yourdomain.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache_bypass $http_upgrade;
    }
}

Health Check

Schemaful exposes a health endpoint for monitoring:

curl https://your-cms.com/api/health

# Response: { "status": "ok", "database": "connected" }