Complete guide for deploying ocrbase on your own infrastructure.
- Bun installed globally
- Docker Desktop running
# Clone and install
git clone https://github.com/majcheradam/ocrbase
cd ocrbase
bun install
# Copy environment file
cp .env.example .env
# Edit .env and set PADDLE_OCR_URL to your PaddleOCR instance
# Start infrastructure (postgres, redis, minio)
docker compose up -d
# Setup database
bun run db:push
# Start API server + worker
bun run devThe API will be available at http://localhost:3000.
To run the full stack as compiled containers (no Bun required on the host):
docker compose --profile prod up -dThis builds and starts the server, web, and worker containers alongside the infrastructure services.
ocrbase requires a running PaddleOCR-VL instance. Deploy it however you prefer (cloud, self-hosted GPU, etc.) and point ocrbase at it:
PADDLE_OCR_URL=https://your-paddleocr-instance.comSee the PaddleOCR deployment docs for setup instructions.
For large PDFs (e.g. ~200 pages), increase the OCR request timeout and reduce worker concurrency:
PADDLE_OCR_TIMEOUT_MS=900000 # 15 minutes
WORKER_CONCURRENCY=1 # avoid saturating the OCR serviceCreate a .env file in the root directory:
# Required
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ocrbase
BETTER_AUTH_SECRET=your-secret-key-at-least-32-characters-long
BETTER_AUTH_URL=http://localhost:3000
CORS_ORIGINS=http://localhost:3001
# Redis
REDIS_URL=redis://localhost:6379
# S3/MinIO Storage
S3_ENDPOINT=http://localhost:9000
S3_REGION=us-east-1
S3_BUCKET=ocrbase
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
# OCR Service
PADDLE_OCR_URL=https://your-paddleocr-instance.com
# The `paddleocr-vl` TypeScript client requires an API key value. For self-hosted
# instances that don't enforce auth, any non-empty string works.
PADDLEOCR_VL_API_KEY=local
PADDLE_OCR_TIMEOUT_MS=900000
WORKER_CONCURRENCY=1
# Optional - LLM for data extraction (required for /v1/extract)
OPENROUTER_API_KEY=your-openrouter-api-key
# Optional - GitHub OAuth
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret| Method | Endpoint | Description |
|---|---|---|
GET |
/v1/health/live |
Liveness check |
GET |
/v1/health/ready |
Readiness check |
POST |
/v1/parse |
Parse document to markdown |
POST |
/v1/extract |
Extract structured data |
GET |
/v1/jobs |
List jobs |
GET |
/v1/jobs/:id |
Get job |
DELETE |
/v1/jobs/:id |
Delete job |
GET |
/v1/jobs/:id/download |
Download result |
POST |
/v1/schemas |
Create schema |
GET |
/v1/schemas |
List schemas |
GET |
/v1/schemas/:id |
Get schema |
PATCH |
/v1/schemas/:id |
Update schema |
DELETE |
/v1/schemas/:id |
Delete schema |
POST |
/v1/schemas/generate |
AI-generate schema |
GET /v1/realtime?job_id=:jobId
Real-time job status updates via SSE. See SDK for type-safe usage.
Interactive documentation (pre-rendered) at: http://localhost:3000/openapi
ocrbase/
├── apps/
│ ├── web/ # Frontend (TanStack Start)
│ └── server/ # Backend API (Elysia)
│ ├── src/
│ │ ├── modules/ # Feature modules (jobs, schemas, health)
│ │ ├── plugins/ # Elysia plugins
│ │ ├── services/ # Core services (OCR, LLM, storage)
│ │ └── workers/ # Background job processors
├── packages/
│ ├── auth/ # Authentication (Better-Auth)
│ ├── config/ # Shared config (tsconfig/eslint)
│ ├── db/ # Database schema (Drizzle)
│ └── env/ # Environment validation
└── docker-compose.yml
| Command | Description |
|---|---|
bun run dev |
Start all services |
bun run dev:server |
Start API only |
bun run dev:web |
Start frontend only |
bun run build |
Build all packages |
bun run check-types |
TypeScript checking |
bun run db:push |
Push schema to DB |
bun run db:studio |
Open Drizzle Studio |
bun run db:migrate |
Run migrations |
| Layer | Technology |
|---|---|
| Runtime | Bun |
| API Framework | Elysia |
| SDK | Eden Treaty |
| Database | PostgreSQL + Drizzle ORM |
| Queue | Redis + BullMQ |
| Storage | S3/MinIO |
| OCR | PaddleOCR-VL 1.5 |
| Auth | Better-Auth |
| Build | Turborepo |