Overview#
Docling Serve is a FastAPI-based HTTP service that wraps the Docling document conversion engine and exposes it as a scalable, deployable API. It listens on port 5001 and is published as a pre-built container image at ghcr.io/docling-project/docling-serve-cpu (plus GPU-enabled variants).
The service is not a thin wrapper — it adds a full async task system with pluggable orchestration backends (Local, RQ, Ray) powered by the docling-jobkit library. Docling Serve owns the HTTP layer, task routing, and status polling; docling-jobkit provides the orchestrators, converter manager, and task/result data models .
The container is built from a CentOS Stream 9 base, bundles mimalloc for memory efficiency, and bakes in ML models (layout, tableformer, picture classifier, rapidocr, easyocr) at image-build time via docling-tools models download . Models are stored at DOCLING_SERVE_ARTIFACTS_PATH (default /opt/app-root/src/.cache/docling/models) .
API Endpoints#
The FastAPI application is defined in docling_serve/app.py. All conversion endpoints accept conversion options (pipeline preset, OCR settings, output formats, etc.) in the request body.
| Endpoint | Description |
|---|---|
GET /health, /ready, /readyz, /livez | Health and Kubernetes liveness/readiness probes |
POST /v1/convert/source | Synchronous conversion from URL(s) |
POST /v1/convert/file | Synchronous conversion from uploaded files |
POST /v1/convert/source/async | Async conversion — returns task_id immediately |
POST /v1/convert/file/async | Async conversion from uploaded files |
POST /v1/convert/source/batch | Batch async conversion |
GET /v1/status/poll/{task_id} | Poll async task status |
WS /v1/status/ws/{task_id} | WebSocket real-time task status updates |
GET /v1/result/{task_id} | Retrieve completed task result |
All endpoints depend on a BaseOrchestrator instance injected via FastAPI dependency injection. The orchestrator backend is selected at startup by DOCLING_SERVE_ENG_KIND and cannot be changed at runtime.
Orchestration Backends#
The orchestration backend is selected via the DOCLING_SERVE_ENG_KIND environment variable (default: local) . The factory in docling_serve/orchestrator_factory.py dynamically imports and configures the chosen backend , all from docling-jobkit.
DOCLING_SERVE_ENG_KIND=local | rq | ray
Local (default)#
Uses docling_jobkit.orchestrators.local.LocalOrchestrator — multiprocessing on a single machine. Key settings:
DOCLING_SERVE_ENG_LOC_NUM_WORKERS(default: 2) — number of worker processesDOCLING_SERVE_ENG_LOC_SHARE_MODELS(default: false) — share ML models across workers
Suitable for development and single-node deployments. No external dependencies required.
RQ (Redis Queue)#
Uses docling_jobkit.orchestrators.rq.RQOrchestrator — distributed job queue backed by Redis. The API pod pushes tasks to a Redis queue; one or more worker pods consume the queue. Key settings :
DOCLING_SERVE_ENG_RQ_REDIS_URL(required) — Redis connection URLDOCLING_SERVE_ENG_RQ_QUEUE_NAME(default:convert)DOCLING_SERVE_ENG_RQ_RESULTS_TTL/DOCLING_SERVE_ENG_RQ_FAILURE_TTL(default: 4 hours each)DOCLING_SERVE_ENG_RQ_REDIS_MAX_CONNECTIONS(default: 50)
Workers are started with docling-serve rq-worker .
Known issue (as of v1.24.0): The RQ engine passes HTTP source URLs directly to Docling without pre-fetching them via jobkit. This means unreachable URLs silently report
task_status: "success"with emptyerrorsarrays, unlike the Ray engine which materializes sources first and retries transient failures. See issue #648 .
Ray#
Uses docling_jobkit.orchestrators.ray.RayOrchestrator — distributed orchestration via Ray Core with fair round-robin scheduling, autoscaling, per-tenant resource limits, and fault tolerance. This is the most advanced backend. Key settings :
DOCLING_SERVE_ENG_RAY_ADDRESS(required) — Ray cluster address ("auto","local", or a cluster URL)DOCLING_SERVE_ENG_RAY_REDIS_URL(required) — Redis for task state and pub/subDOCLING_SERVE_ENG_RAY_MIN_ACTORS/DOCLING_SERVE_ENG_RAY_MAX_ACTORS— autoscaling boundsDOCLING_SERVE_ENG_RAY_MAX_CONCURRENT_TASKS(default: 5) — per-tenant concurrency capDOCLING_SERVE_ENG_RAY_TENANT_ID_HEADER(default:X-Tenant-Id) — header for multi-tenant routing- Timeout settings:
DOCLING_SERVE_ENG_RAY_TASK_TIMEOUT,DOCLING_SERVE_ENG_RAY_DOCUMENT_TIMEOUT,DOCLING_SERVE_ENG_RAY_DISPATCHER_RPC_TIMEOUT
Validation at startup enforces that RQ requires eng_rq_redis_url and Ray requires both eng_ray_redis_url and eng_ray_address .
Deployment Configurations#
All deployment manifests live under docs/deploy-examples/ and are documented in docs/deployment.md .
Docker Compose (local GPU)#
| Variant | Manifest | Requirements |
|---|---|---|
| NVIDIA | compose-nvidia.yaml | nvidia drivers ≥550.54.14, nvidia-container-toolkit |
| AMD ROCm | compose-amd.yaml | AMDGPU driver ≥6.3, ROCm ≥6.3 |
Both expose port 5001 and are started with docker compose -f <manifest> up -d .
Kubernetes / OpenShift#
| Manifest | Description |
|---|---|
docling-serve-simple.yaml | Single-pod Deployment + Service with NVIDIA CUDA |
docling-serve-rq-workers.yaml | API Deployment + 2 RQ Worker Deployments + Redis Deployment |
docling-serve-oauth.yaml | oauth-proxy sidecar for authentication, TLS via cluster CA, OpenShift Route |
docling-serve-replicas-w-sticky-sessions.yaml | 3 replicas with OpenShift Route sticky sessions |
The RQ workers manifest deploys three separate Kubernetes workloads: the API server (1 replica), RQ worker pods (2 replicas by default), and Redis . Redis credentials are stored in a Kubernetes Secret and injected as DOCLING_SERVE_ENG_RQ_REDIS_URL and REDIS_PASSWORD .
The sticky sessions configuration is needed when using the local engine with multiple replicas, because async task state is held in-process — requests for a given task_id must reach the same pod .
The oauth-proxy variant secures the service with TLS encryption between all components and authentication via OpenShift's built-in OAuth server .
Docling-Jobkit Integration#
docling-jobkit is the orchestration library Docling Serve depends on, declared as docling-jobkit[rq,ray,vlm]>=2.0.0,<3.0.0 .
What jobkit provides to docling-serve:
BaseOrchestrator— abstract interface for all three backendsLocalOrchestrator,RQOrchestrator,RayOrchestrator— backend implementationsDoclingConverterManager/DoclingConverterManagerConfig— manages the Docling pipeline (VLM, OCR, layout, table structure, picture classification presets)Task,TaskSource— task data modelStoredSuccessOutcome,StoredFailureOutcome— result data modelS3PresignedConfig— S3 source/target connector configuration
The orchestrator_factory.py _build_cm_config() function maps all Docling Serve settings to jobkit's DoclingConverterManagerConfig , controlling VLM pipeline, picture description, code/formula handling, and OCR engine presets. S3 presigned URL configuration is built and injected here as well .
Jobkit also ships standalone CLIs (docling-jobkit-local, docling-jobkit-multiproc) for batch document processing without the HTTP service layer .