Self-hosted video streaming + image optimization platform. The open-source alternative to Mux + Cloudinary + CloudFront.
Built with Grit — Go + React.
- HLS Video Streaming — Multi-quality adaptive bitrate (360p–1080p), sprite hover previews
- Image Transform API — On-demand resize, crop, format conversion with cache-as-redirect
- React SDK —
@mediakit-dev/reactwith 6 components: VideoPlayer, VideoUploader, MediaImage, ImageUploader, EmbedCode, MediaGallery - Embed Script — Single
<script>tag to embed videos on any website - AI Analysis — Video summaries, chapter generation, content moderation via Vercel AI Gateway
- Private Assets — JWT-signed URLs for paid/premium content
- Webhooks — HMAC-signed event delivery with retry logic
- Analytics — Redis-first event ingestion, play counts, watch time
- Multi-Storage — Cloudflare R2, AWS S3, Backblaze B2, MinIO
- API Keys — Programmatic access with scopes (
mk_live_prefix)
# 1. Install Grit CLI
go install github.com/MUKE-coder/grit/v3/cmd/grit@latest
# 2. Scaffold
grit new mediakit --triple --next --style default
cd mediakit
# 3. Start infrastructure (Postgres + Redis + MinIO)
docker compose up -d
# 4. Install dependencies
pnpm install
# 5. Run migrations and seed
cd apps/api && go run cmd/server/main.go migrate && go run cmd/server/main.go seed && cd ../..
# 6. Start development
pnpm dev| Service | URL |
|---|---|
| Go API | http://localhost:8080 |
| Web + Docs | http://localhost:3000 |
| Admin Panel | http://localhost:3001 |
Default admin login: admin@example.com / password
See DEPLOYMENT.md for the full guide. Quick summary:
Point to this repo, set compose path to docker-compose.prod.yml.
Copy .env.production.example → Dokploy environment tab. Fill in:
# Your domains
APP_URL=https://mediakitapi.gritcms.com
OAUTH_FRONTEND_URL=https://mediakitadmin.gritcms.com
CORS_ORIGINS=https://mediakit.gritcms.com,https://mediakitadmin.gritcms.com,https://mediakitapi.gritcms.com
API_URL=https://mediakitapi.gritcms.com
ADMIN_URL=https://mediakitadmin.gritcms.com
# Generate secrets
JWT_SECRET=<openssl rand -hex 32>
SIGNED_URL_SECRET=<openssl rand -hex 32>
SENTINEL_SECRET_KEY=<openssl rand -hex 32>
POSTGRES_PASSWORD=<openssl rand -base64 24>
# Cloudflare R2
STORAGE_DRIVER=r2
R2_ENDPOINT=https://ACCOUNT_ID.r2.cloudflarestorage.com
R2_ACCESS_KEY=...
R2_SECRET_KEY=...
R2_BUCKET=your-bucket| Domain | Container | Port |
|---|---|---|
mediakit.gritcms.com |
mediakit-web | 3000 |
mediakitapi.gritcms.com |
mediakit-api | 8080 |
mediakitadmin.gritcms.com |
mediakit-admin | 3000 |
# After first deploy, SSH into VPS:
docker exec -it mediakit-api ./server migrate
docker exec -it mediakit-api ./server seed- Login to admin at
https://mediakitadmin.gritcms.com(admin@example.com / password) - Change password immediately via Profile page
- Upload a test video via System → Files
- Watch it transcode in the Videos section
- Create an API key for your application
- Set up webhooks if you need event notifications
- Configure Cloudflare DNS — see DEPLOYMENT.md for DNS records and caching rules
Full docs are available at the web app's /docs route:
- Introduction — What is MediaKit
- Quick Start — Setup guide
- Admin Guide — What to do after login
- Upload Pipeline — Presigned URL uploads
- Video Streaming — HLS transcoding
- Image Transforms — On-demand image API
- React SDK — 6 drop-in components
- Embed Script — Single script tag embed
- Analytics — Play tracking
- Webhooks — Event delivery
- AI Analysis — Summaries, chapters, moderation
- Private Assets — Signed URLs
- API Keys — Programmatic access
npm install @mediakit-dev/reactimport { MediaKitProvider, VideoPlayer, MediaImage } from '@mediakit-dev/react'
<MediaKitProvider config={{ baseUrl: 'https://mediakitapi.gritcms.com' }}>
<VideoPlayer videoId="1" />
<MediaImage assetId="42" width={800} height={600} fit="cover" />
</MediaKitProvider><script src="https://mediakit.gritcms.com/mediakit-embed.js" data-id="1"></script>| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/mediakit/uploads/presign |
JWT/Key | Get presigned upload URL |
| POST | /api/mediakit/uploads/complete |
JWT/Key | Confirm upload |
| GET | /api/mediakit/videos/:id/playback |
Public | Playback info |
| GET | /api/mediakit/videos/:id/progress |
JWT | SSE transcode progress |
| GET | /api/img/:id?w=&h=&fit=&format= |
Public | Image transform |
| POST | /api/analytics/events |
Public | Ingest play event |
| GET | /api/analytics/summary |
JWT/Key | Workspace stats |
| POST | /api/ai/videos/:id/analyse |
JWT | Trigger AI analysis |
| POST | /api/keys |
JWT | Create API key |
| POST | /api/webhooks |
JWT | Create webhook |
| Layer | Technology |
|---|---|
| Backend | Go 1.24 + Gin + GORM |
| Database | PostgreSQL 16 |
| Cache / Jobs | Redis 7 + asynq |
| Storage | Cloudflare R2 / AWS S3 / Backblaze B2 / MinIO |
| Video | FFmpeg (HLS transcoding) |
| Frontend | Next.js 16 + React 19 + Tailwind CSS |
| Monorepo | Turborepo + pnpm |
| AI | Vercel AI Gateway |
MIT