A self-hosted web interface for Docling that converts PDFs to Markdown with OCR and table extraction, packaged as a single Docker container.
Docker Hub · API Docs (local) · Report an Issue
Docling Web wraps the Docling document-conversion library in a production-ready web application. Upload PDFs through a batch-capable UI, track conversion progress in real time, and download the extracted Markdown — all without configuring Python environments or ML dependencies on your host machine.
Running Docling locally requires installing heavy ML dependencies, managing model caches, and writing glue code for batch processing. Docling Web solves this by packaging everything into a single Docker image with a polished frontend, persistent job queue, and zero host-side setup.
Queue PDFs with shared and per-file settings for OCR, table extraction, and image handling.
Monitor queued and processing jobs, inspect the original PDF alongside the generated Markdown.
- Batch PDF upload with shared defaults and per-file setting overrides
- Real-time job progress tracking (queued → processing → serializing → bundling → done)
- Side-by-side PDF source and Markdown result viewer
- Individual file download or full batch ZIP export
- Persistent SQLite-backed job queue with automatic retry isolation (failed jobs don't block the batch)
- Docling ML model cache persisted across container restarts
- Backend: FastAPI, Python 3.11, SQLAlchemy, Uvicorn
- Frontend: React 19, TypeScript, Vite, TanStack Query
- Data: SQLite (
app.db) - AI: Docling 2.84 (OCR, table structure, layout analysis)
- Infra: Docker, Docker Compose, GitHub Actions (Docker Hub publish)
┌─────────────────────────────────────────────────┐
│ Docker Container │
│ │
│ ┌──────────────┐ ┌─────────────────────┐ │
│ │ React SPA │──────▶│ FastAPI (Uvicorn) │ │
│ │ (static) │ │ port 8176 │ │
│ └──────────────┘ └──────┬──────────────┘ │
│ │ │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌────────┐ ┌─────────┐ │
│ │ Worker │ │ SQLite │ │ Storage │ │
│ │Coordinator│ │ (queue)│ │ (files) │ │
│ └─────┬─────┘ └────────┘ └─────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ Docling │ │
│ │ (ML) │ │
│ └──────────┘ │
│ │
│ Volumes: /data (uploads, results, bundles, db) │
│ ~/.cache/docling (ML model cache) │
└────────────────────────────────────────────────────┘
The application runs as a modular monolith in a single container. Uvicorn
serves both the FastAPI API endpoints and the compiled React SPA as static
files. An in-process WorkerCoordinator polls the SQLite queue and dispatches
conversion jobs to Docling. Docker volumes persist application data and the ML
model cache across restarts.
docling-web/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI app factory and API routes
│ │ ├── config.py # Pydantic settings (env vars)
│ │ ├── models.py # SQLAlchemy ORM models
│ │ ├── schemas.py # Pydantic request/response schemas
│ │ ├── repositories.py # Database query layer
│ │ ├── database.py # Engine and session management
│ │ ├── storage.py # File system storage manager
│ │ └── services/
│ │ ├── worker.py # Background job coordinator
│ │ ├── docling_adapter.py # Docling conversion wrapper
│ │ └── bundler.py # ZIP bundle builder
│ ├── tests/
│ └── requirements.txt
├── frontend/
│ ├── src/
│ │ ├── App.tsx # Root application component
│ │ ├── components/ # Reusable UI components
│ │ ├── routes/ # Page-level route components
│ │ ├── lib/ # API client and utilities
│ │ └── styles.css # Global styles
│ ├── index.html
│ ├── vite.config.ts
│ └── package.json
├── docs/images/ # Screenshots for README
├── docker-compose.yml # Default Docker compose
├── docker-compose.dev.yml # Dev compose (hot reload)
├── Dockerfile # Multi-stage Docker build
├── Dockerfile.dev # Development build targets
├── Makefile # Project task runner
└── README.md
- Docker and Docker Compose
Pull and run the pre-built image:
docker run -d \
-p 6176:8176 \
-v docling-data:/data \
-v docling-cache:/root/.cache/docling \
akl49879/docling-web:latestOpen http://localhost:6176 in your browser.
git clone https://github.com/akl773/docling-web.git
cd docling-web
make up| URL | Purpose |
|---|---|
| http://localhost:6176 | Web interface |
| http://localhost:8176/api/docs | Swagger API documentation |
All environment variables are set in docker-compose.yml (or docker-compose.dev.yml for development). No .env file is required by default.
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
Yes | sqlite:////data/app.db |
SQLite connection string |
DATA_DIR |
Yes | /data |
Root path for uploads, results, and bundles |
OMP_NUM_THREADS |
No | 4 |
Thread count for PyTorch / Docling inference |
MAX_CONCURRENT_JOBS |
No | 1 |
Max parallel background conversion workers |
UVICORN_WORKERS |
No | 2 |
Uvicorn worker process count for the default Docker setup |
FRONTEND_DIST_DIR |
No | /app/frontend-dist |
Path to compiled React SPA assets |
PYTHONUNBUFFERED |
No | 1 |
Disable Python output buffering |
# Default Docker setup (detached)
make up
# Development with hot reload (backend + frontend)
make dev
# Stop
make down
# View logs
make logs
# Clean up containers and volumes
make clean- Open the web UI at http://localhost:6176.
- Drag and drop one or more PDF files onto the upload area.
- Configure shared conversion settings (OCR, table extraction, image handling) or set per-file overrides.
- Submit the batch. The UI tracks progress through stages: queued → processing → serializing → bundling → done.
- Click a completed job to view the original PDF alongside the extracted Markdown.
- Download individual Markdown files or the entire batch as a ZIP.
The first conversion takes longer because Docling downloads ML models (~1–2 GB) into the persistent
docling_cachevolume. Subsequent runs use the cached models.
The backend exposes a RESTful API under /api. Full interactive docs are
available at /api/docs (Swagger UI) and /api/redoc (ReDoc).
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health |
Health check |
POST |
/api/batches |
Upload PDFs and create a conversion batch |
GET |
/api/batches |
List all batches |
GET |
/api/batches/{id} |
Get batch details |
GET |
/api/batches/{id}/download |
Download batch results as ZIP |
GET |
/api/jobs |
List jobs (optionally filter by ?status=) |
GET |
/api/jobs/{id} |
Get job details |
GET |
/api/jobs/{id}/source |
View original PDF |
GET |
/api/jobs/{id}/markdown |
View extracted Markdown |
GET |
/api/jobs/{id}/download |
Download Markdown file |
make help # Show all available Makefile targets
make dev # Start dev environment with hot reload (Docker)
make up # Start default Docker environment
make down # Stop environment
make ps # Show container status
make logs # Follow all logs
make logs-backend # Follow backend logs only
make clean # Remove containers and volumesThe dev environment (make dev) uses docker-compose.dev.yml which:
- Mounts
backend/app/for live Python reload - Mounts
frontend/src/for Vite HMR - Runs the frontend dev server on port 6176 with an API proxy to the backend on port 8176
The project ships with a GitHub Actions workflow that publishes to Docker Hub
on every tagged release (v*):
git tag v1.0.0
git push origin v1.0.0This triggers .github/workflows/docker-publish.yml, which builds the
multi-stage Dockerfile and pushes both the version tag and latest to
akl49879/docling-web.
- Fork the repository.
- Create a feature branch from
main. - Make changes and verify with
make dev. - Open a pull request.

