Skip to content

Configuration Guide

All extraction behavior is controlled through ExtractionConfig. Pass it directly in code or load it from a TOML/YAML/JSON file. Every field is optional. For per-field documentation, see the Configuration Reference.

Python
import asyncio
from xberg import ExtractInput, extract, ExtractionConfig
async def main() -> None:
config = ExtractionConfig(
use_cache=True,
enable_quality_processing=True
)
result = await extract(ExtractInput(uri="document.pdf"), config)
print(result.results[0].content)
asyncio.run(main())

Three formats are supported. TOML is recommended.

xberg.toml
use_cache = true
enable_quality_processing = true
[ocr]
backend = "tesseract"
language = "eng"
[ocr.tesseract_config]
psm = 3

When no --config path is supplied, Xberg walks up from the current working directory looking for xberg.toml and uses the first match. If no project-local file is found, it falls back to a per-user global config at xberg/xberg.{toml,yaml,yml,json} in the platform config directory — $XDG_CONFIG_HOME (or ~/.config) on Linux, ~/Library/Application Support on macOS, and %APPDATA% on Windows. In the project walk, YAML and JSON files are supported only when passed explicitly via --config. If nothing is found, defaults are used.

Python
import asyncio
from xberg import ExtractInput, ExtractionConfig, extract
async def main() -> None:
config: ExtractionConfig = ExtractionConfig()
result = await extract(ExtractInput(uri="document.pdf"), config)
content: str = result.results[0].content
content_preview: str = content[:100]
print(f"Content preview: {content_preview}")
print(f"Total length: {len(content)}")
asyncio.run(main())

ExtractionConfig::apply_env_overrides() applies XBERG_* variables on top of an already-loaded config. Each variable that is set overrides the matching config-file value; unset variables are ignored. The serve and mcp commands call it automatically after loading the config. The extract and batch commands do not apply it — use flags or --config-json there.

Variable Overrides
XBERG_OCR_LANGUAGE OCR language (ISO 639 code, e.g. eng, deu)
XBERG_OCR_BACKEND OCR backend (tesseract, paddle-ocr, sceptre, vlm)
XBERG_DISABLE_OCR Disable OCR entirely (true/false)
XBERG_CHUNKING_MAX_CHARS Maximum characters per chunk
XBERG_CHUNKING_MAX_OVERLAP Overlap between chunks
XBERG_CHUNKING_TOKENIZER HuggingFace tokenizer model ID for token-based sizing
XBERG_CACHE_ENABLED Cache flag (true/false)
XBERG_TOKEN_REDUCTION_MODE Token reduction level (off, light, moderate, aggressive, maximum)
XBERG_OUTPUT_FORMAT Output format
XBERG_LAYOUT_PRESET Layout detection preset (fast, accurate)
XBERG_LLM_MODEL LLM model for structured extraction
XBERG_LLM_API_KEY API key for the structured-extraction LLM provider
XBERG_LLM_BASE_URL Custom base URL for the LLM provider
XBERG_VLM_OCR_MODEL VLM model for vision-based OCR
XBERG_VLM_EMBEDDING_MODEL LLM model for embedding generation
XBERG_EMBEDDING_PLUGIN_NAME Name of a registered in-process embedding backend

Server-only variables (XBERG_HOST, XBERG_PORT, XBERG_CORS_ORIGINS, XBERG_MAX_REQUEST_BODY_BYTES, XBERG_MAX_MULTIPART_FIELD_BYTES) configure the API/MCP server, not extraction.

For the extract and batch commands, sources are applied highest to lowest:

  1. Individual CLI flags (--ocr, --output-format, --chunk, …)
  2. Inline JSON (--config-json or --config-json-base64) — merged field by field, not whole-object
  3. Config file — explicit --config, otherwise the auto-discovered xberg.toml
  4. Built-in defaults

The serve and mcp commands add environment variables on top of the loaded config via apply_env_overrides(), so a set XBERG_* variable overrides the config-file value in those modes.

Python
import asyncio
from xberg import ExtractInput, ExtractionConfig, OcrConfig, TesseractConfig, extract
async def main() -> None:
config: ExtractionConfig = ExtractionConfig(
ocr=OcrConfig(
backend="tesseract", language="eng+fra",
tesseract_config=TesseractConfig(psm=3)
)
)
result = await extract(ExtractInput(uri="document.pdf"), config)
print(result.results[0].content)
asyncio.run(main())

For backend selection and language packs, see OCR Guide. For fine-grained Tesseract tuning, see TesseractConfig Reference.

For Sceptre, use the backend name sceptre and place its sections directly in backend_options:

xberg.toml
[ocr]
backend = "sceptre"
language = ["eng", "deu"]
[ocr.backend_options.recognition]
batch_size = 4
[ocr.backend_options.concurrency]
max_threads = 2

Do not nest these options under backend_options.sceptre. Custom Rust builds use sceptre-ocr for the ONNX Runtime desktop/server backend or sceptre-ocr-tract for Android and iOS. WebAssembly support uses the opt-in Sceptre worker build/API because the model and tract runtime size are not part of the default wasm-target bundle. Use ocr.language for language selection; it overrides backend_options.model.languages. Leave backend_options.model.backend unset so Xberg can select ORT or tract for the target. The supported option paths are backend_options.detection.*, backend_options.recognition.*, backend_options.concurrency.max_threads, backend_options.model.cache_dir, backend_options.model.registry_owner, backend_options.model.detector_path, and backend_options.model.recognizer_path. cache_dir and automatic model download apply only to desktop/server ORT builds. Android and iOS exclude the downloader; both model paths are required and must reference application-resolved bundle or asset files.

Python
from xberg import (
ExtractionConfig,
ChunkingConfig,
EmbeddingConfig,
EmbeddingModelType,
)
config: ExtractionConfig = ExtractionConfig(
chunking=ChunkingConfig(
max_characters=1500,
overlap=200,
embedding=EmbeddingConfig(
model=EmbeddingModelType.preset("balanced")
),
)
)

ConcurrencyConfig.max_threads caps every internal thread pool at once: the global Rayon pool, ONNX Runtime intra-op threads, and the combined document/worker budget used by batch extraction.

When max_threads is left unset, the effective budget is min(detected_cpu_cores, 8) — not “use all available cores”. This 8-core ceiling is a deliberate serverless/shared-tenant default, not an auto-scaling target. On a host with more than 8 cores, the extra cores go unused by default:

  • Bare metal / VM with no CPU quota: max_threads must be set explicitly above 8 to use more than 8 cores. There is no other way to exceed the default ceiling on this class of host.
  • Linux containers under a cgroup CPU quota (e.g. Kubernetes resources.limits.cpu): the quota is used as the ceiling instead of the hardcoded 8, since the quota already reflects a deliberately-configured resource limit. This applies automatically; no configuration is needed.

If none of the above applies and the host has more than 8 cores, a one-time WARN-level log is emitted the first time the thread budget is resolved, naming the detected core count and the applied cap — so the ceiling is discoverable without reading source.

[concurrency]
max_threads = 32