Docling Serve is configured almost entirely through environment variables prefixed DOCLING_SERVE_. There are close to 180 of them in the current release, and the published configuration doc lists roughly half. This page lists all of them.
Every name, type and default below is read from docling_serve/settings.py at the v1.32.0 tag, released September 1, 2026, with the engine settings cross-checked against docling-jobkit 3.5.0, which is the version that release pins. Where the doc and the source disagree, the source wins and the difference is called out.
This is the reference companion to two guides: Docling Serve: self-hosting the Docling REST API covers the endpoints, async jobs and timeouts, and Docling Docker: CPU/GPU images, Compose and model cache covers the container side. If you only want the Compose file, skip to it.
How Docling Serve reads configuration
The settings object is a pydantic-settings model with env_prefix="DOCLING_SERVE_". A field named max_sync_wait is therefore set by DOCLING_SERVE_MAX_SYNC_WAIT. Five things about the loader are worth knowing before the tables:
- Precedence is env var, then
.envfile, then config file, then defaults. Thesettings_customise_sourcesoverride in the source orders theminit > env > dotenv > yaml_config > file_secret. A.envin the working directory is read automatically.DOCLING_SERVE_CONFIG_FILEpoints at a YAML or JSON file whose keys are the field names without the prefix (max_sync_wait: 300), and env vars override anything in it. - Typos are silent. The model is declared with
extra="allow", soDOCLING_SERVE_MAX_SYNC_WAIT_SECONDSdoes not raise; it is stored and ignored. Check/versionor your logs rather than assuming a setting took. - Empty string means unset.
env_parse_none_str=""maps""toNonefor optional fields. That is why-e DOCLING_SERVE_ARTIFACTS_PATH=""clears the artifacts path that the container image sets, which re-enables model auto-download. - Lists are JSON unless a validator says otherwise.
DOCLING_SERVE_CORS_ORIGINSmust be a JSON array:'["https://app.example.com"]'. TheALLOWED_*allow-lists andALLOWED_IMAGE_EXPORT_MODEShave a validator that also accepts a comma-separated string. TheCUSTOM_*_PRESETSsettings must be JSON objects; a value that fails to parse becomes{}rather than an error. - Booleans take the usual pydantic spellings.
true,false,1,0,yes,no,on,off, case-insensitive.
The CLI exposes only --artifacts-path and --enable-ui at the app level. As of v1.32.0 the run command re-exports both as environment variables before starting Uvicorn, so they survive --reload and multi-worker spawns; every other app setting has no CLI flag at all. Configure through the environment and you never hit the gap.
Types below use Python notation from the source: str, int, float, bool, Path, list[str], dict. Optional[X] means unset by default.
Web server (UVICORN_*)
These are not DOCLING_SERVE_ variables but they live in the same settings module and you will need at least one of them.
| Variable | Type | Default | Effect |
|---|---|---|---|
UVICORN_HOST | str | 0.0.0.0 | Bind address. docling-serve dev overrides to localhost |
UVICORN_PORT | int | 5001 | Bind port |
UVICORN_WORKERS | Optional[int] | unset (Uvicorn uses 1) | Server processes. Keep at 1; each process loads its own models, and the local engine’s task store is per-process |
UVICORN_RELOAD | bool | false | Code auto-reload. dev sets it true |
UVICORN_ROOT_PATH | str | "" | ASGI root path when mounted under a prefix behind a proxy |
UVICORN_PROXY_HEADERS | bool | true | Trust X-Forwarded-* for client address |
UVICORN_TIMEOUT_KEEP_ALIVE | int | 60 | Keep-alive timeout in seconds |
UVICORN_SSL_CERTFILE | Optional[Path] | unset | TLS certificate |
UVICORN_SSL_KEYFILE | Optional[Path] | unset | TLS key |
UVICORN_SSL_KEYFILE_PASSWORD | Optional[str] | unset | TLS key passphrase |
Because the default bind is 0.0.0.0 and authentication is off, publish the container port to loopback (-p 127.0.0.1:5001:5001) unless a proxy with TLS sits in front.
Paths, models and startup
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_CONFIG_FILE | Optional[Path] | unset | YAML or JSON file of settings. Env vars override it. Missing file raises at startup |
DOCLING_SERVE_ARTIFACTS_PATH | Optional[Path] | unset in code; /opt/app-root/src/.cache/docling/models in the official images | Directory the model weights are loaded from. When set, a missing model is a hard error, not a download. Not to be confused with DOCLING_ARTIFACTS_PATH, which configures the Docling library itself |
DOCLING_SERVE_STATIC_PATH | Optional[Path] | unset | Directory of static assets for the API docs and UI, for offline deployments. Mounted at /static when the directory exists |
DOCLING_SERVE_SCRATCH_PATH | Optional[Path] | unset (a temp dir is created) | Working directory for results awaiting fetch. With SINGLE_USE_RESULTS=false this grows without bound |
DOCLING_SERVE_LOAD_MODELS_AT_BOOT | bool | true | Warm the converter cache at startup so /ready reflects real readiness. No-op under the rq engine, where models live in the workers |
DOCLING_SERVE_OPTIONS_CACHE_SIZE | int | 2 | How many DocumentConverter instances, each with its loaded models, to keep. Every distinct option combination a client sends occupies a slot |
DOCLING_SERVE_ENABLE_UI | bool | false | Serve the Gradio playground at /ui. Install with the ui extra |
DOCLING_SERVE_API_HOST | str | localhost | Host the UI uses to reach the API. Only read by the Gradio UI; set it when the UI runs behind a different hostname |
OPTIONS_CACHE_SIZE is the one people miss. Two clients that differ only in table_mode are two cache entries, and each holds a full model set in memory. Size it to the number of option combinations you actually serve, and watch memory when you raise it.
Request limits and policy
These are enforced server-side and return 422 when violated.
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_MAX_DOCUMENT_TIMEOUT | float | 604800 (7 days) | Ceiling for document_timeout. Also the value substituted when a request omits it. Set this; a bad scan can otherwise hold a worker for a week |
DOCLING_SERVE_MAX_NUM_PAGES | int | sys.maxsize (unbounded) | Reject documents with more pages than this |
DOCLING_SERVE_MAX_FILE_SIZE | int | sys.maxsize (unbounded) | Reject inputs larger than this many bytes |
DOCLING_SERVE_MAX_SOURCES_PER_REQUEST | int | 3 | Maximum sources entries, or files on the multipart endpoint, per request. A fourth is rejected |
DOCLING_SERVE_MAX_IMAGES_SCALE | float | 2.0 | Ceiling for images_scale. Values above it are rejected, not clamped |
DOCLING_SERVE_ALLOWED_IMAGE_EXPORT_MODES | Optional[list[str]] | unset (all three) | Restrict image_export_mode to a subset of placeholder, referenced, embedded. Unknown names are dropped silently |
DOCLING_SERVE_ALLOWED_SOURCE_TYPES | Optional[list[str]] | unset (built-in kinds) | Allow-list of source kinds. Plugin-registered sources must be listed explicitly; local_path is never available remotely |
DOCLING_SERVE_ALLOWED_TARGET_TYPES | Optional[list[str]] | unset (built-in kinds) | Allow-list of target kinds, same rules as sources |
MAX_FILE_SIZE and MAX_NUM_PAGES are unbounded by default. Set both before you accept untrusted uploads.
Sync endpoints and results
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_MAX_SYNC_WAIT | int | 120 | Seconds a sync endpoint (/v1/convert/source, /v1/convert/file) waits before returning 504. The task is not cancelled when it fires |
DOCLING_SERVE_SYNC_POLL_INTERVAL | int | 2 | Seconds between the sync handler’s checks on its own task |
DOCLING_SERVE_SINGLE_USE_RESULTS | bool | true | Schedule a result for removal once it has been fetched. false keeps results in the scratch directory indefinitely |
DOCLING_SERVE_RESULT_REMOVAL_DELAY | int | 300 | Grace period in seconds between the first fetch and removal, when single-use is on |
Raising MAX_SYNC_WAIT is the last resort, not the first. The sync handler enqueues the task and polls it; on timeout it raises 504 and leaves the conversion running, with a TODO: abort task! at that point in the source. The Serve guide’s timeout section walks through the order of fixes.
Security and exposure
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_API_KEY | str | "" (auth off) | Shared secret. When set, every API route requires the X-Api-Key header, including status polls and result fetches. Websockets take ?api_key=. Health and metrics endpoints stay open |
DOCLING_SERVE_CORS_ORIGINS | list[str] | ["*"] | Allowed cross-origin origins. JSON array only |
DOCLING_SERVE_CORS_METHODS | list[str] | ["*"] | Allowed cross-origin methods |
DOCLING_SERVE_CORS_HEADERS | list[str] | ["*"] | Allowed cross-origin request headers |
DOCLING_SERVE_SHOW_VERSION_INFO | bool | true | /version returns package versions. false makes it 403 |
DOCLING_SERVE_ENABLE_MANAGEMENT_ENDPOINTS | bool | false | Enable /v1/memory/* statistics. Otherwise 403 |
DOCLING_SERVE_DEBUG_ERROR_DETAILS | bool | false | Return raw internal exception text in HTTP and task errors. Off, infrastructure-origin errors are sanitised |
DOCLING_SERVE_ENABLE_REMOTE_SERVICES | bool | false | Allow pipeline components to make outbound calls, for example a VLM served over an API. Off keeps processing local |
DOCLING_SERVE_ALLOW_EXTERNAL_PLUGINS | bool | false | Load third-party connector and model plugins. The packages must be installed in every API and worker process |
There is no per-tenant credential, rate limit or quota. If you need any of that, it goes in a proxy in front of Docling Serve.
Logging
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_LOG_LEVEL | Optional[WARNING|INFO|DEBUG] | unset (resolves to WARNING) | Verbosity. Case-insensitive. -v / -vv on the CLI override it |
DOCLING_SERVE_LOG_FORMAT | text|json | text | json emits one structured object per line; use it for anything that aggregates logs |
DOCLING_SERVE_LOG_HEADER_PREFIX | str | X-Docling-Log- | Request headers matching this prefix are stripped of the prefix and attached to every log line for that request. X-Docling-Log-RequestID: abc becomes "RequestID": "abc" |
The header propagation is the cheapest request tracing available here, and it works under the local engine without any extra setup.
Pipeline batching
These flow straight into docling-jobkit’s DoclingConverterManagerConfig. They are all unset by default, which means the library’s own defaults apply.
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_QUEUE_MAX_SIZE | Optional[int] | unset | Size of the page queue between pipeline stages, so the upper bound on pages open at once |
DOCLING_SERVE_OCR_BATCH_SIZE | Optional[int] | unset | Pages per batch in the OCR stage |
DOCLING_SERVE_LAYOUT_BATCH_SIZE | Optional[int] | unset | Pages per batch in layout detection |
DOCLING_SERVE_TABLE_BATCH_SIZE | Optional[int] | unset | Pages per batch in table structure |
DOCLING_SERVE_BATCH_POLLING_INTERVAL_SECONDS | Optional[float] | unset | How long a stage waits to gather pages before starting a batch |
Two Docling library variables belong next to them, because they decide how many CPU threads and which device the conversion uses:
| Variable | Default | Effect |
|---|---|---|
DOCLING_NUM_THREADS | 4 | Torch CPU threads inside conversion. Set at or below the container CPU limit |
DOCLING_DEVICE | unset (auto) | cpu, cuda, cuda:N, or mps |
DOCLING_PERF_PAGE_BATCH_SIZE | 4 | Pages processed per batch in the library |
DOCLING_PERF_ELEMENTS_BATCH_SIZE | 8 | Document elements per batch during enrichment |
OMP_NUM_THREADS | 4 in the official images | OpenMP thread pool |
Async engine
DOCLING_SERVE_ENG_KIND picks which engine runs the async endpoints and, under local, the sync ones too.
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_KIND | local|rq|ray | local | local runs conversions in-process. rq dispatches to Redis-backed RQ workers. ray dispatches to a Ray cluster with Redis for state |
Local engine (ENG_LOC_*)
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_LOC_NUM_WORKERS | int | 2 | Worker threads pulling tasks from the in-process queue, so concurrent conversions per process |
DOCLING_SERVE_ENG_LOC_SHARE_MODELS | bool | false | Share one model set across those threads. Off, each worker thread allocates its own copy |
SHARE_MODELS=true is the easiest memory saving available. The default allocates a full model graph per worker, so two workers cost roughly twice the memory of one. Pending tasks under local live in the process and are lost on restart.
RQ engine (ENG_RQ_*)
Set ENG_KIND=rq on the API containers and the workers alike, run workers with docling-serve rq-worker, and the API stops converting entirely. The Redis URL is validated at startup; the process refuses to boot without it.
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RQ_REDIS_URL | str | "" (required) | Redis connection URL, e.g. redis://redis:6379/ |
DOCLING_SERVE_ENG_RQ_QUEUE_NAME | str | convert | Queue name shared by API instances and workers |
DOCLING_SERVE_ENG_RQ_RESULTS_PREFIX | str | docling:results | Key prefix for stored results |
DOCLING_SERVE_ENG_RQ_SUB_CHANNEL | str | docling:updates | Pub/sub channel workers use to report status |
DOCLING_SERVE_ENG_RQ_RESULTS_TTL | int | 14400 (4 h) | Seconds a successful job’s result is kept in Redis |
DOCLING_SERVE_ENG_RQ_FAILURE_TTL | int | 14400 (4 h) | Seconds a failed job is kept. Not in the configuration doc |
DOCLING_SERVE_ENG_RQ_JOB_TIMEOUT | int | 14400 (4 h) | Maximum runtime per job before the worker aborts it. Baked in at enqueue time, so set it on the API side. -1 disables. 0 does not: RQ reads 0 as unset and applies its own 180-second default |
DOCLING_SERVE_ENG_RQ_REDIS_MAX_CONNECTIONS | int | 50 | Connection pool size. 50 covers 1–4 workers, 100 for 5–10, 150–200 beyond |
DOCLING_SERVE_ENG_RQ_REDIS_SOCKET_TIMEOUT | Optional[float] | unset | Socket timeout for Redis operations |
DOCLING_SERVE_ENG_RQ_REDIS_SOCKET_CONNECT_TIMEOUT | Optional[float] | unset | Socket connect timeout |
DOCLING_SERVE_ENG_RQ_REDIS_GATE_CONCURRENCY | Optional[int] | unset (MAX_CONNECTIONS − RESERVED, min 1) | Concurrent caller-facing Redis operations allowed. Not in the configuration doc |
DOCLING_SERVE_ENG_RQ_REDIS_GATE_RESERVED_CONNECTIONS | int | 10 | Pool connections held back for background work when computing the gate default |
DOCLING_SERVE_ENG_RQ_REDIS_GATE_WAIT_TIMEOUT | float | 0.25 | Seconds a submit or result fetch waits for a gate slot before failing |
DOCLING_SERVE_ENG_RQ_REDIS_GATE_STATUS_POLL_WAIT_TIMEOUT | float | 5.0 | Same, for status polls |
DOCLING_SERVE_ENG_RQ_ZOMBIE_REAPER_INTERVAL | float | 300.0 | Seconds between sweeps of the API’s task-tracking table |
DOCLING_SERVE_ENG_RQ_ZOMBIE_REAPER_MAX_AGE | float | 3600.0 | Tracked tasks older than this with no live job are dropped from the API’s view |
The gate settings exist so that a burst of status polls cannot exhaust the Redis pool and starve the background listener; the four GATE_* values and the two ZOMBIE_REAPER_* values are undocumented upstream and were read from the jobkit RQOrchestratorConfig. Leave them alone unless you see gate-timeout errors in the logs.
Ray engine (ENG_RAY_*)
The Ray engine requires both a Redis URL and a Ray address, and refuses to start without either. It is also the largest settings surface in the module and is not covered by the upstream configuration doc at all. Defaults below are Docling Serve’s own, which in a few places differ from jobkit’s.
Connection and storage:
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RAY_REDIS_URL | str | "" (required) | Redis URL. Standard, Sentinel (redis+sentinel://) and Cluster (?cluster=true) forms are accepted |
DOCLING_SERVE_ENG_RAY_ADDRESS | str | "" (required) | Ray cluster address. auto or local are passed to Ray as “auto-detect or start local” |
DOCLING_SERVE_ENG_RAY_NAMESPACE | str | docling | Ray namespace for isolation |
DOCLING_SERVE_ENG_RAY_RUNTIME_ENV | Optional[dict] | unset | Ray runtime environment, as JSON |
DOCLING_SERVE_ENG_RAY_ENABLE_MTLS | bool | false | mTLS to the Ray cluster |
DOCLING_SERVE_ENG_RAY_CLUSTER_NAME | Optional[str] | unset | Cluster name for certificate generation; required when mTLS is on |
DOCLING_SERVE_ENG_RAY_REDIS_MAX_CONNECTIONS | int | 50 | Pool size |
DOCLING_SERVE_ENG_RAY_REDIS_SOCKET_TIMEOUT | Optional[float] | unset | Socket timeout |
DOCLING_SERVE_ENG_RAY_REDIS_SOCKET_CONNECT_TIMEOUT | Optional[float] | unset | Socket connect timeout |
DOCLING_SERVE_ENG_RAY_REDIS_GATE_CONCURRENCY | Optional[int] | unset | Concurrent caller-facing Redis operations |
DOCLING_SERVE_ENG_RAY_REDIS_GATE_RESERVED_CONNECTIONS | int | 10 | Connections held back for internal work |
DOCLING_SERVE_ENG_RAY_REDIS_GATE_WAIT_TIMEOUT | float | 0.25 | Gate wait for submits and fetches |
DOCLING_SERVE_ENG_RAY_REDIS_GATE_STATUS_POLL_WAIT_TIMEOUT | float | 5.0 | Gate wait for status polls |
DOCLING_SERVE_ENG_RAY_REDIS_OPERATION_TIMEOUT | float | 30.0 | Timeout per Redis operation |
DOCLING_SERVE_ENG_RAY_RESULTS_TTL | int | 14400 (4 h) | Result lifetime in Redis |
DOCLING_SERVE_ENG_RAY_RESULTS_PREFIX | str | docling:ray:results | Result key prefix |
DOCLING_SERVE_ENG_RAY_SUB_CHANNEL | str | docling:ray:updates | Pub/sub channel for task updates |
DOCLING_SERVE_ENG_RAY_SCRATCH_DIR | Optional[Path] | unset (falls back to SCRATCH_PATH) | Scratch directory for the Ray orchestrator |
DOCLING_SERVE_ENG_RAY_LOG_LEVEL | str | INFO | Log level for the Ray orchestrator |
Fairness and per-tenant limits. Tenants are identified by a request header:
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RAY_TENANT_ID_HEADER | str | X-Tenant-Id | Header the API reads to attribute a request to a tenant |
DOCLING_SERVE_ENG_RAY_MAX_CONCURRENT_TASKS | int | 5 | Tasks in flight per tenant |
DOCLING_SERVE_ENG_RAY_MAX_QUEUED_TASKS | Optional[int] | unset (unlimited) | Queued tasks per tenant |
DOCLING_SERVE_ENG_RAY_ENABLE_QUEUE_LIMIT_REJECTION | bool | false | Return 429 when the queue limit is hit, instead of waiting |
DOCLING_SERVE_ENG_RAY_MAX_DOCUMENTS | Optional[int] | unset (unlimited) | Documents in processing per tenant |
DOCLING_SERVE_ENG_RAY_ENABLE_DOCUMENT_LIMITS | bool | false | Enforce MAX_DOCUMENTS |
DOCLING_SERVE_ENG_RAY_DISPATCHER_INTERVAL | float | 30.0 | Slow-path resync cadence; the dispatcher also wakes immediately on new work |
DOCLING_SERVE_ENG_RAY_SUPERVISOR_POLL_INTERVAL | float | 5.0 | Seconds between supervisor health checks |
Autoscaling and resources:
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RAY_MIN_ACTORS | int | 1 | Converter replica lower bound |
DOCLING_SERVE_ENG_RAY_MAX_ACTORS | int | 10 | Converter replica upper bound |
DOCLING_SERVE_ENG_RAY_TARGET_REQUESTS_PER_REPLICA | float > 0 | 1.0 | Autoscaling target of concurrent requests per replica |
DOCLING_SERVE_ENG_RAY_MAX_ONGOING_REQUESTS_PER_REPLICA | Optional[int] | unset (follows the target) | Hard cap on in-flight requests per replica |
DOCLING_SERVE_ENG_RAY_CONVERTER_MAX_REPLICAS_PER_NODE | Optional[int] | unset (no cap) | Converter replicas per Ray node, 1–100 |
DOCLING_SERVE_ENG_RAY_UPSCALE_DELAY_S | float | 30.0 | Wait before scaling up |
DOCLING_SERVE_ENG_RAY_DOWNSCALE_DELAY_S | float | 600.0 | Wait before scaling down |
DOCLING_SERVE_ENG_RAY_GRACEFUL_SHUTDOWN_WAIT_LOOP_S | Optional[float] | unset (Ray Serve default) | Seconds between drain checks during replica shutdown |
DOCLING_SERVE_ENG_RAY_GRACEFUL_SHUTDOWN_TIMEOUT_S | Optional[float] | unset (Ray Serve default) | Maximum drain wait before a replica is killed |
DOCLING_SERVE_ENG_RAY_CONVERTER_ACTOR_NUM_CPUS | float | 1.0 | CPU request per converter replica. ENG_RAY_NUM_CPUS_PER_ACTOR is accepted as a deprecated alias and logs a warning |
DOCLING_SERVE_ENG_RAY_CONVERTER_ACTOR_MEMORY_REQUEST | Optional[str] | unset | Memory request per converter replica, e.g. 8GB or 8Gi. ENG_RAY_MEMORY_LIMIT_PER_ACTOR is the deprecated alias |
DOCLING_SERVE_ENG_RAY_DISPATCHER_NUM_CPUS | float | 0.25 | CPU request for the dispatcher actor |
DOCLING_SERVE_ENG_RAY_DISPATCHER_MEMORY_REQUEST | Optional[str] | unset | Memory request for the dispatcher actor |
DOCLING_SERVE_ENG_RAY_OBJECT_STORE_MEMORY | Optional[str] | unset | Ray object store size |
DOCLING_SERVE_ENG_RAY_ENABLE_OOM_PROTECTION | bool | true | Monitor actor memory and act before the OS OOM killer does |
DOCLING_SERVE_ENG_RAY_MEMORY_WARNING_THRESHOLD | float | 0.9 | Fraction of the memory request at which warnings start |
Page-slice fan-out and coordinators. With fan-out enabled, a large PDF is split into page ranges converted in parallel and reassembled by a coordinator replica:
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RAY_ENABLE_PDF_PAGE_SLICE_FANOUT | bool | false | Split eligible PDFs into page slices |
DOCLING_SERVE_ENG_RAY_MAX_PAGE_SLICE_SIZE | int | 32 | Pages per slice. Docling Serve’s default; jobkit’s own is 10 |
DOCLING_SERVE_ENG_RAY_MAX_PAGE_SLICE_PARALLELISM | Optional[int] | unset (falls back to MAX_CONCURRENT_TASKS) | Docling Serve still computes and passes this, but jobkit 3.5.0 marks it deprecated and ignored; fan-out concurrency is governed per tenant by MAX_CONCURRENT_TASKS |
DOCLING_SERVE_ENG_RAY_COORDINATOR_MIN_ACTORS | Optional[int] | unset (MIN_ACTORS) | Coordinator replica lower bound |
DOCLING_SERVE_ENG_RAY_COORDINATOR_MAX_ACTORS | Optional[int] | unset (MAX_ACTORS) | Coordinator replica upper bound |
DOCLING_SERVE_ENG_RAY_COORDINATOR_TARGET_REQUESTS_PER_REPLICA | Optional[float > 0] | unset | Coordinator autoscaling target |
DOCLING_SERVE_ENG_RAY_COORDINATOR_MAX_ONGOING_REQUESTS_PER_REPLICA | int | 8 | Hard cap on in-flight requests per coordinator |
DOCLING_SERVE_ENG_RAY_COORDINATOR_MAX_REPLICAS_PER_NODE | Optional[int] | unset (no cap) | Coordinator replicas per node |
DOCLING_SERVE_ENG_RAY_COORDINATOR_ACTOR_NUM_CPUS | float | 0.25 | CPU request per coordinator |
DOCLING_SERVE_ENG_RAY_COORDINATOR_ACTOR_MEMORY_REQUEST | Optional[str] | unset | Memory request per coordinator |
Retries, timeouts and health:
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ENG_RAY_MAX_TASK_RETRIES | int | 3 | Retries for a failed task |
DOCLING_SERVE_ENG_RAY_RETRY_DELAY | float | 5.0 | Seconds between task retries |
DOCLING_SERVE_ENG_RAY_MAX_DOCUMENT_RETRIES | int | 2 | Retries per document within a task |
DOCLING_SERVE_ENG_RAY_DISPATCHER_MAX_RESTARTS | int | -1 (unlimited) | Dispatcher actor restarts |
DOCLING_SERVE_ENG_RAY_DISPATCHER_MAX_TASK_RETRIES | int | 3 | Ray-level retries for dispatcher operations |
DOCLING_SERVE_ENG_RAY_TASK_TIMEOUT | Optional[float] | 3600.0 | Maximum seconds per task; empty disables |
DOCLING_SERVE_ENG_RAY_DOCUMENT_TIMEOUT | Optional[float] | 300.0 | Maximum seconds per document; empty disables. Note this is five minutes, far below the API-level MAX_DOCUMENT_TIMEOUT |
DOCLING_SERVE_ENG_RAY_DISPATCHER_RPC_TIMEOUT | float | 5.0 | Timeout for one dispatcher health-check RPC |
DOCLING_SERVE_ENG_RAY_LIVENESS_FAIL_AFTER | float | 90.0 | Seconds of continuous unhealthiness before /livez fails so Kubernetes restarts the pod |
DOCLING_SERVE_ENG_RAY_ENABLE_HEARTBEAT | bool | true | Dispatcher heartbeat monitoring |
If you do not already operate Ray, run RQ. The Ray engine is designed for multi-tenant clusters and its defaults assume one.
Artifact storage
Enables the PresignedUrlTarget, where the server writes converted output to object storage and returns a presigned URL instead of the document body. Off by default.
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_ARTIFACT_STORAGE_ENABLED | bool | false | Turn managed artifact storage on |
DOCLING_SERVE_ARTIFACT_STORAGE_BACKEND | s3|azure | s3 | Which backend |
DOCLING_SERVE_ARTIFACT_STORAGE_ENDPOINT | str | "" | S3 endpoint host, without protocol |
DOCLING_SERVE_ARTIFACT_STORAGE_VERIFY_SSL | bool | true | Verify the S3 endpoint’s TLS certificate. false for plain-HTTP or self-signed MinIO |
DOCLING_SERVE_ARTIFACT_STORAGE_BUCKET | str | "" | S3 bucket |
DOCLING_SERVE_ARTIFACT_STORAGE_ACCESS_KEY | str | "" | S3 access key |
DOCLING_SERVE_ARTIFACT_STORAGE_SECRET_KEY | str | "" | S3 secret key |
DOCLING_SERVE_ARTIFACT_STORAGE_KEY_PREFIX | str | converted/ | S3 object key prefix |
DOCLING_SERVE_ARTIFACT_STORAGE_AZURE_CONNECTION_STRING | str | "" | Azure connection string. Must carry AccountName and AccountKey; managed identity and SAS-only strings are not supported |
DOCLING_SERVE_ARTIFACT_STORAGE_AZURE_CONTAINER | str | "" | Azure Blob container |
DOCLING_SERVE_ARTIFACT_STORAGE_AZURE_ACCOUNT_NAME | str | "" | Azure account name; must match the connection string |
DOCLING_SERVE_ARTIFACT_STORAGE_AZURE_BLOB_PREFIX | str | converted/ | Azure blob name prefix |
DOCLING_SERVE_ARTIFACT_STORAGE_PRESIGN_TTL_SECONDS | int | 3600 | Lifetime of the returned presigned or SAS URL. Documented range 60–604800 |
With the Azure backend, the connection string, container and account name are all checked at startup and a missing one raises with the variable names in the message.
Model presets and allow-lists
These decide which models a client may ask for and what "default" means. They pass through to the converter manager unchanged. The pattern repeats for each model family: a DEFAULT_* preset, an optional ALLOWED_* list that restricts clients to a subset, a CUSTOM_* JSON object that registers new presets, and an ALLOW_CUSTOM_*_CONFIG flag that lets clients send a fully custom configuration instead of a preset name.
ALLOWED_* lists accept a JSON array or a comma-separated string. CUSTOM_* presets must be JSON objects mapping a preset id to that family’s options.
VLM pipeline:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_VLM_PRESET | str | granite_docling |
DOCLING_SERVE_ALLOWED_VLM_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_VLM_PRESETS | dict | {} |
DOCLING_SERVE_ALLOWED_VLM_ENGINES | Optional[list[str]] | unset (all) |
DOCLING_SERVE_ALLOW_CUSTOM_VLM_CONFIG | bool | false |
Picture description:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_PICTURE_DESCRIPTION_PRESET | str | smolvlm |
DOCLING_SERVE_ALLOWED_PICTURE_DESCRIPTION_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_PICTURE_DESCRIPTION_PRESETS | dict | {} |
DOCLING_SERVE_ALLOWED_PICTURE_DESCRIPTION_ENGINES | Optional[list[str]] | unset (all) |
DOCLING_SERVE_ALLOW_CUSTOM_PICTURE_DESCRIPTION_CONFIG | bool | false |
Code and formula enrichment:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_CODE_FORMULA_PRESET | str | default |
DOCLING_SERVE_ALLOWED_CODE_FORMULA_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_CODE_FORMULA_PRESETS | dict | {} |
DOCLING_SERVE_ALLOWED_CODE_FORMULA_ENGINES | Optional[list[str]] | unset (all) |
DOCLING_SERVE_ALLOW_CUSTOM_CODE_FORMULA_CONFIG | bool | false |
Picture classification:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_PICTURE_CLASSIFICATION_PRESET | str | document_figure_classifier_v2 |
DOCLING_SERVE_ALLOWED_PICTURE_CLASSIFICATION_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_PICTURE_CLASSIFICATION_PRESETS | dict | {} |
DOCLING_SERVE_ALLOW_CUSTOM_PICTURE_CLASSIFICATION_CONFIG | bool | false |
Table structure. Table and layout have both a kind (which implementation) and a preset (which configuration of it):
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_TABLE_STRUCTURE_KIND | str | docling_tableformer |
DOCLING_SERVE_ALLOWED_TABLE_STRUCTURE_KINDS | Optional[list[str]] | unset (all; the default kind is always allowed) |
DOCLING_SERVE_DEFAULT_TABLE_STRUCTURE_PRESET | str | tableformer_v1_accurate |
DOCLING_SERVE_ALLOWED_TABLE_STRUCTURE_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_TABLE_STRUCTURE_PRESETS | dict | {} |
DOCLING_SERVE_ALLOW_CUSTOM_TABLE_STRUCTURE_CONFIG | bool | false |
Layout:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_LAYOUT_KIND | str | docling_layout_default |
DOCLING_SERVE_ALLOWED_LAYOUT_KINDS | Optional[list[str]] | unset (all; the default kind is always allowed) |
DOCLING_SERVE_DEFAULT_LAYOUT_PRESET | str | docling_layout_default |
DOCLING_SERVE_ALLOWED_LAYOUT_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_LAYOUT_PRESETS | dict | {} |
DOCLING_SERVE_ALLOW_CUSTOM_LAYOUT_CONFIG | bool | false |
OCR. Not in the upstream configuration doc:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_OCR_KIND | str | auto |
DOCLING_SERVE_DEFAULT_OCR_PRESET | str | auto |
DOCLING_SERVE_ALLOWED_OCR_KINDS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_ALLOWED_OCR_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_OCR_PRESETS | dict | {} |
DOCLING_SERVE_ALLOW_CUSTOM_OCR_CONFIG | bool | false |
Chunking, for the /v1/chunk/* endpoints. Also undocumented upstream:
| Variable | Type | Default |
|---|---|---|
DOCLING_SERVE_DEFAULT_CHUNKING_PRESET | str | granite_embedding_278m |
DOCLING_SERVE_ALLOWED_CHUNKING_PRESETS | Optional[list[str]] | unset (all) |
DOCLING_SERVE_CUSTOM_CHUNKING_PRESETS | dict | {} |
The four ALLOW_CUSTOM_*_CONFIG flags for table structure, layout, picture classification and OCR are wired through orchestrator_factory.py but absent from the configuration doc, which lists only the VLM, picture description and code/formula ones.
Telemetry
| Variable | Type | Default | Effect |
|---|---|---|---|
DOCLING_SERVE_OTEL_ENABLE_METRICS | bool | true | Collect OpenTelemetry metrics |
DOCLING_SERVE_OTEL_ENABLE_TRACES | bool | false | Collect traces. Needs OTEL_EXPORTER_OTLP_ENDPOINT. Under RQ this also wraps the queue so trace context reaches the workers |
DOCLING_SERVE_OTEL_ENABLE_PROMETHEUS | bool | true | Serve /metrics in Prometheus format |
DOCLING_SERVE_OTEL_ENABLE_OTLP_METRICS | bool | false | Also export metrics over OTLP |
DOCLING_SERVE_OTEL_SERVICE_NAME | str | docling-serve | Service name on emitted telemetry |
DOCLING_SERVE_METRICS_PORT | Optional[int] | unset | Serve /metrics on a separate port instead of the API port. A bind failure raises at startup |
OTEL_EXPORTER_OTLP_ENDPOINT is a standard OpenTelemetry variable, not a DOCLING_SERVE_ one, but traces and OTLP metrics go nowhere without it.
Docker Compose example
A single-container Compose file that sets the variables which matter before real traffic arrives. Models ship inside the official image, so there is no volume and no download step. The Docker guide defends each choice; this version adds an API key and a CORS restriction.
services:
docling:
image: quay.io/docling-project/docling-serve-cpu:v1.32.0
ports:
- '127.0.0.1:5001:5001'
environment:
# Server
UVICORN_WORKERS: '1'
DOCLING_NUM_THREADS: '4'
OMP_NUM_THREADS: '4'
# Local engine
DOCLING_SERVE_ENG_LOC_NUM_WORKERS: '2'
DOCLING_SERVE_ENG_LOC_SHARE_MODELS: 'true'
# Limits
DOCLING_SERVE_MAX_DOCUMENT_TIMEOUT: '1800'
DOCLING_SERVE_MAX_SYNC_WAIT: '120'
DOCLING_SERVE_MAX_FILE_SIZE: '52428800'
DOCLING_SERVE_MAX_NUM_PAGES: '200'
DOCLING_SERVE_MAX_SOURCES_PER_REQUEST: '3'
# Exposure
DOCLING_SERVE_API_KEY: 'replace-me'
DOCLING_SERVE_CORS_ORIGINS: '["https://app.example.com"]'
DOCLING_SERVE_SHOW_VERSION_INFO: 'false'
# Logging
DOCLING_SERVE_LOG_LEVEL: 'INFO'
DOCLING_SERVE_LOG_FORMAT: 'json'
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:5001/ready', timeout=5).read()"
interval: 30s
timeout: 10s
retries: 5
start_period: 180s
stop_grace_period: 2m
restart: unless-stopped
deploy:
resources:
limits:
cpus: '4'
memory: 12G
GPU images: cu128 and cu130
Four official images exist, mirrored on quay.io/docling-project/ and ghcr.io/docling-project/:
| Image | Torch build | Arch |
|---|---|---|
docling-serve | PyPI torch, CUDA libraries included | amd64, arm64 |
docling-serve-cpu | CPU-only torch | amd64, arm64 |
docling-serve-cu128 | CUDA 12.8 torch | amd64 |
docling-serve-cu130 | CUDA 13.0 torch | amd64, arm64 |
The CUDA images are deliberately not tagged latest, only with explicit versions and main, so that a deprecated CUDA build cannot arrive through a floating tag. Pin the version and match the tag to your host driver: a cu128 image needs a driver that supports the CUDA 12.8 runtime, cu130 needs 13.0.
As a Compose override on the file above:
services:
docling:
image: quay.io/docling-project/docling-serve-cu128:v1.32.0
environment:
DOCLING_DEVICE: 'cuda'
NVIDIA_VISIBLE_DEVICES: 'all'
NVIDIA_DRIVER_CAPABILITIES: 'compute,utility'
runtime: nvidia
Swap in docling-serve-cu130:v1.32.0 for a CUDA 13.0 host. DOCLING_DEVICE is a Docling library variable, not a Docling Serve one, and it is the thing that actually moves the layout and table models onto the GPU. OCR through RapidOCR’s ONNX backend can still fall back to CPU silently; the Serve guide covers the check.
Scaling out with RQ
Three services: Redis, the API, and workers built from the same image with a different command. ENG_RQ_JOB_TIMEOUT sits on the API service because it is baked into each job at enqueue time.
services:
redis:
image: redis:7-alpine
command: ['redis-server', '--appendonly', 'yes']
volumes:
- redis-data:/data
docling-api:
image: quay.io/docling-project/docling-serve-cpu:v1.32.0
ports:
- '127.0.0.1:5001:5001'
environment:
DOCLING_SERVE_ENG_KIND: 'rq'
DOCLING_SERVE_ENG_RQ_REDIS_URL: 'redis://redis:6379/'
DOCLING_SERVE_ENG_RQ_JOB_TIMEOUT: '3600'
DOCLING_SERVE_MAX_DOCUMENT_TIMEOUT: '1800'
DOCLING_SERVE_API_KEY: 'replace-me'
DOCLING_SERVE_LOG_FORMAT: 'json'
depends_on:
- redis
docling-worker:
image: quay.io/docling-project/docling-serve-cpu:v1.32.0
command: ['docling-serve', 'rq-worker']
environment:
DOCLING_SERVE_ENG_KIND: 'rq'
DOCLING_SERVE_ENG_RQ_REDIS_URL: 'redis://redis:6379/'
DOCLING_NUM_THREADS: '4'
OMP_NUM_THREADS: '4'
DOCLING_SERVE_LOG_FORMAT: 'json'
depends_on:
- redis
deploy:
replicas: 2
resources:
limits:
memory: 12G
volumes:
redis-data:
Under RQ the API’s /ready gates on its queue processor and Redis connection, not on whether a worker has loaded its models. Probe the workers separately. The project’s Kubernetes manifest is the same shape.
Self-hosting versus a hosted Docling API
Everything on this page is the cost of owning Docling Serve: a model cache, thread caps, an engine choice, Redis, timeouts at three layers, and a readiness probe that means what it says. That is a fair trade when you need formats beyond PDF, control over OCR, a pinned Docling version, or processing that never leaves your network. It is a poor trade when you wanted Markdown out of a PDF and nothing else.
If the second one is you, Parsebridge runs Docling as a managed API. It is our own product, so here is the honest scope: PDF in, Markdown out, through our request shape rather than Docling Serve’s. No DOCLING_SERVE_ variables, no Compose file, no /ready probe:
curl -X POST https://api.parsebridge.com/v1/parse/url \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/document.pdf"}'
If you already run Docling Serve and it is behaving, stay there. Same parser either way.
Names, types and defaults above were read from docling_serve/settings.py, orchestrator_factory.py and policy.py at the v1.32.0 tag, with engine semantics from the docling-jobkit 3.5.0 RQ and Ray orchestrator configs. Descriptions that the upstream configuration doc does not provide were inferred from how the value is used in code, and are marked as such. The Compose files are source-reviewed against that release, not runtime-tested here.