Stirling-PDF is a self-hosted, enterprise-capable PDF manipulation platform built on a multi-module architecture spanning Java (Spring Boot), TypeScript (React/Mantine), Rust (Tauri), and Python (FastAPI). This guide covers every operational and development concern for administrators, DevOps engineers, and contributors working with Stirling-PDF version 2.9.2.
1. Architecture Overview
Stirling-PDF follows a modular monorepo structure with four distinct runtime components that can be deployed together or independently.
1.1 Component Map
┌─────────────────────────────────────────────────────────────┐
│ Stirling-PDF v2.9.2 │
├──────────────┬──────────────┬───────────────┬───────────────┤
│ Backend │ Frontend │ Desktop │ AI Engine │
│ Spring Boot │ React/Vite │ Tauri/Rust │ Python/FastAPI│
│ 4.0.5 │ Mantine UI │ │ pydantic-ai │
│ Java 21 │ TypeScript │ │ │
├──────────────┼──────────────┼───────────────┼───────────────┤
│ app/common │ frontend/src │ frontend/ │ engine/src/ │
│ app/core │ /core │ src-tauri/ │ stirling/ │
│ app/ │ /proprietary│ │ api/ │
│ proprietary │ /saas │ │ agents/ │
│ │ /desktop │ │ │
└──────────────┴──────────────┴───────────────┴───────────────┘
1.2 Backend Modules
The Spring Boot backend is split into three Gradle subprojects:
| Module | Path | Purpose |
|---|---|---|
| common | app/common/ |
Shared models, configuration classes, annotations, cross-cutting services (TaskManager, FileStorage, EndpointConfiguration) |
| core | app/core/ |
All PDF operation controllers (19 controller files), core configuration (19 config files), PDF manipulation via Apache PDFBox 3.0.7 |
| proprietary | app/proprietary/ |
Enterprise features: OAuth2, SAML2, SSO, user/role management, audit logging, workflows. Licensed under Stirling PDF User License |
The application entry point is stirling.software.SPDF.SPDFApplication. The embedded servlet container is not Tomcat — the build explicitly excludes spring-boot-starter-tomcat in favor of Jetty/Undertow.
1.3 Frontend Architecture
The React frontend uses Vite as the build tool and is organized into four feature domains:
| Domain | Path | Contents |
|---|---|---|
| core | frontend/src/core/ |
47 service files, 49 utility files, page editor with undo/redo command pattern, PDFium WASM rendering, i18n (40+ locales) |
| proprietary | frontend/src/proprietary/ |
Auth flows, Stripe checkout, workflow builder, enterprise configuration UI |
| saas | frontend/src/saas/ |
SaaS deployment: onboarding, billing, PostHog analytics |
| desktop | frontend/src/desktop/ |
Tauri bridge services, backend health monitoring, connection mode management, operation routing |
Note
The frontend uses PDFium compiled to WebAssembly for client-side PDF rendering and manipulation. This means many operations execute entirely in the browser without round-tripping to the backend.
1.4 Desktop Application (Tauri)
The desktop app wraps the React frontend in a native Rust shell (frontend/src-tauri/). Tauri commands expose:
- Auth: save/get/clear tokens for enterprise auth
- Backend management: spawn, monitor, and manage a local backend process
- Connection modes: local backend, remote server, or hybrid
- File handling: native file dialogs, drag-and-drop, default PDF handler registration
- Native print: OS-level print integration
- Platform detection: Windows/macOS/Linux-specific behavior
A Windows thumbnail handler DLL (stirling_thumbnail_handler.dll) implements the COM IThumbnailProvider interface, enabling PDF preview thumbnails directly in Windows Explorer. A provisioner tool supports enterprise deployment by locking the server URL in configuration.
1.5 AI Engine
The Python FastAPI service (engine/src/stirling/api/app.py) provides AI-powered PDF operations using pydantic-ai:
| Agent | Role |
|---|---|
OrchestratorAgent |
Routes user natural-language requests to the correct tool/agent |
PdfEditAgent |
AI-guided PDF editing based on user instructions |
PdfQuestionAgent |
Answers questions about PDF content |
UserSpecAgent |
Drafts and revises user specifications from requirements |
ExecutionPlanningAgent |
Plans multi-step PDF operation sequences |
MathAuditorAgent |
Audits financial/math PDFs, verifies ledger entries |
API routes: /draft, /revise, /next-action, /examine, /deliberate, /orchestrate, /pdf_edit, /pdf_questions, /health.
1.6 Dependency Stack
| Layer | Technology | Version |
|---|---|---|
| JVM | Java | 21 (source/target), 25 (compilation toolchain) |
| Framework | Spring Boot | 4.0.5 |
| PDF manipulation | Apache PDFBox | 3.0.7 |
| Cryptography | BouncyCastle | 1.83 |
| Image I/O | TwelveMonkeys imageio | 3.13.1 |
| Code generation | Lombok | 1.18.44 |
| SAML | Spring Security SAML | 7.0.4 |
| SAML (impl) | OpenSAML | 5.2.1 |
| Markdown | Commonmark | 0.28.0 |
| Frontend framework | React + Mantine UI | — |
| Frontend build | Vite | — |
| Frontend routing | React Router | — |
| Frontend i18n | i18next | — |
| Desktop | Tauri | — |
| AI runtime | FastAPI + pydantic-ai | — |
2. Requirements & Prerequisites
2.1 Hardware Requirements
| Deployment | CPU | RAM | Disk |
|---|---|---|---|
| Ultra-lite (Java-only ops) | 1 core | 512 MB | 500 MB |
| Standard (with external tools) | 2 cores | 2 GB | 2 GB |
| Fat (all dependencies) | 2+ cores | 4 GB | 5 GB |
| With AI engine | 2+ cores | 4+ GB | 6 GB |
2.2 Software Requirements
For Docker deployment (recommended):
- Docker Engine 20.10+
- Docker Compose v2
For bare-metal / development:
- Java 21 JDK (compilation requires Java 25 toolchain)
- Node.js (for frontend build)
- Gradle (wrapper included)
- Optional external tools: LibreOffice, qpdf, Ghostscript, Tesseract OCR, OpenCV, Python 3.x, unoconvert
Important
The fat Docker image bundles all external tools. The standard image requires you to install LibreOffice, Tesseract, and other CLI tools separately if you need endpoints that depend on them. The ultra-lite image intentionally excludes all external dependencies.
3. Configuration Mastery
3.1 settings.yml
The primary configuration file is mounted at /configs/settings.yml inside the container. It controls all runtime behavior. Configuration keys map to Spring properties via relaxed binding.
3.2 Environment Variables — Complete Reference
All configuration can be set via environment variables, which override settings.yml values.
System Configuration
| Variable | Default | Description |
|---|---|---|
SYSTEM_DEFAULTLOCALE |
en-US |
Default UI language. Supports 40+ locales |
SYSTEM_MAXFILESIZE |
100 |
Maximum upload file size in megabytes |
SYSTEM_ROOTURIPATH |
(empty) | Base URI path for reverse proxy deployments (e.g., /stirling-pdf) |
SYSTEM_GOOGLEVISIBILITY |
false |
When true, allows search engine indexing via robots.txt |
SYSTEM_ENABLEMOBILESCANNER |
(unset) | Enables mobile document scanner via WebRTC camera access |
Security Configuration
| Variable | Default | Description |
|---|---|---|
DOCKER_ENABLE_SECURITY |
false |
Master switch for security features (OAuth2, SAML2, user management) |
SECURITY_ENABLELOGIN |
false |
Enables the login page and session-based authentication |
SECURITY_CUSTOMGLOBALAPIKEY |
(unset) | Sets a global API key accepted via X-API-KEY header for all requests |
UI Configuration
| Variable | Default | Description |
|---|---|---|
UI_APPNAME |
Stirling-PDF |
Application name displayed in the UI |
UI_HOMEDESCRIPTION |
(unset) | Custom homepage description text |
UI_APPNAMENAVBAR |
(unset) | Custom name in the navigation bar (overrides UI_APPNAME in navbar only) |
Container & Process Configuration
| Variable | Default | Description |
|---|---|---|
MODE |
BOTH |
Container operating mode: BOTH (full stack), FRONTEND (UI only), BACKEND (API only) |
BACKEND_INTERNAL_PORT |
8081 |
Internal backend port when MODE=BOTH |
VITE_API_BASE_URL |
(unset) | Backend URL when running frontend-only (MODE=FRONTEND) |
PUID |
1000 |
Process user ID inside container |
PGID |
1000 |
Process group ID inside container |
UMASK |
022 |
File creation mask |
JAVA_CUSTOM_OPTS |
(unset) | Additional JVM flags passed to the Java process |
STIRLING_JVM_PROFILE |
balanced |
JVM tuning profile: balanced (G1GC) or performance (Shenandoah GC) |
FAT_DOCKER |
false |
Set true when using the fat Docker image to enable all tool-dependent endpoints |
Feature Toggles
| Variable | Default | Description |
|---|---|---|
DISABLE_ADDITIONAL_FEATURES |
false |
When true, disables all endpoints requiring external CLI tools |
ENDPOINTS_GROUPS_TO_REMOVE |
(unset) | Comma-separated list of endpoint groups to disable (e.g., CLI,Python,OpenCV) |
METRICS_ENABLED |
true |
Enables Prometheus-compatible metrics endpoint |
SHOW_SURVEY |
(unset) | Shows feedback survey prompt in the UI |
OCR & Language Configuration
| Variable | Default | Description |
|---|---|---|
TESSERACT_LANGS |
(unset) | Comma-separated Tesseract OCR language codes to install (e.g., eng,fra,deu) |
LANGS |
(unset) | Supported UI languages |
Storage Configuration
| Variable | Default | Description |
|---|---|---|
STORAGE_LOCAL_BASEPATH |
(unset) | Base filesystem path for local file storage (enterprise feature) |
LibreOffice / UNO Server Configuration
| Variable | Default | Description |
|---|---|---|
PROCESS_EXECUTOR_AUTO_UNO_SERVER |
true |
Automatically starts a local UNO server for LibreOffice operations |
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_HOST |
(unset) | Hostname of remote UNO server endpoint (N = 0, 1, 2, ...) |
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_PORT |
2003 |
Port for remote UNO server endpoint |
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_HOST_LOCATION |
(unset) | Set to remote for remote UNO servers |
PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_N_PROTOCOL |
http |
Protocol for UNO server communication |
PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT |
(unset) | Maximum concurrent LibreOffice conversion sessions |
AI Engine Configuration
| Variable | Default | Description |
|---|---|---|
STIRLING_SMART_MODEL |
(unset) | AI model for complex reasoning tasks (e.g., gpt-4) |
STIRLING_FAST_MODEL |
(unset) | AI model for quick tasks (e.g., gpt-3.5-turbo) |
STIRLING_SMART_MODEL_MAX_TOKENS |
(unset) | Max output tokens for smart model |
STIRLING_FAST_MODEL_MAX_TOKENS |
(unset) | Max output tokens for fast model |
STIRLING_LOG_LEVEL |
(unset) | Engine log level |
STIRLING_LOG_FILE |
(unset) | Engine log file path |
STIRLING_POSTHOG_ENABLED |
(unset) | Enable PostHog telemetry in AI engine |
STIRLING_POSTHOG_API_KEY |
(unset) | PostHog project API key |
STIRLING_POSTHOG_HOST |
(unset) | PostHog instance URL |
Tip
For resource-constrained environments, set
STIRLING_JVM_PROFILE=balancedandPROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT=1to prevent LibreOffice from consuming excessive memory during concurrent conversions.
3.3 Volume Mounts
| Container Path | Purpose | Required |
|---|---|---|
/configs |
settings.yml and configuration files |
Recommended |
/logs |
Application log output | Recommended |
/usr/share/tessdata |
Tesseract OCR language data files | Only for OCR |
/customFiles |
UI customization assets (logos, CSS overrides) | Optional |
/pipeline |
Pipeline/automation configuration files | Optional |
/tmp/stirling-pdf |
Shared temp directory for remote UNO server operations | Only for remote UNO |
4. Deployment
4.1 Docker Images
Stirling-PDF provides four Dockerfile variants targeting different use cases:
| Variant | Dockerfile | Size | External Tools | Use Case |
|---|---|---|---|---|
| Standard | Dockerfile |
~800 MB | Some (configurable) | General purpose |
| Fat | Dockerfile.fat |
~2.5 GB | All bundled | Full feature set, no external deps to manage |
| Ultra-lite | Dockerfile.ultra-lite |
~300 MB | None | Java-only PDF operations, minimal footprint |
| Unified | Dockerfile.unified |
Varies | Configurable | Split frontend/backend or combined via MODE env var |
4.2 Standard Deployment (Docker Compose)
version: "3.8"
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest
ports:
- "8080:8080"
volumes:
- ./configs:/configs
- ./logs:/logs
- ./customFiles:/customFiles
environment:
- DOCKER_ENABLE_SECURITY=false
- SYSTEM_MAXFILESIZE=100
- SYSTEM_DEFAULTLOCALE=en-US
restart: unless-stopped
4.3 Fat Docker Deployment
version: "3.8"
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest-fat
ports:
- "8080:8080"
volumes:
- ./configs:/configs
- ./logs:/logs
- ./tessdata:/usr/share/tessdata
- ./pipeline:/pipeline
environment:
- FAT_DOCKER=true
- TESSERACT_LANGS=eng,fra,deu,spa
- SYSTEM_MAXFILESIZE=500
restart: unless-stopped
Note
The fat image bundles LibreOffice, Tesseract, qpdf, Ghostscript, OpenCV, and Python. Set
FAT_DOCKER=trueso the endpoint configuration system knows all tool dependencies are satisfied.
4.4 Ultra-lite Deployment
version: "3.8"
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest-ultra-lite
ports:
- "8080:8080"
volumes:
- ./configs:/configs
environment:
- DISABLE_ADDITIONAL_FEATURES=true
restart: unless-stopped
The ultra-lite image supports only Java-native PDF operations: merge, split, rotate, rearrange, remove pages, add watermark, encrypt/decrypt, metadata editing, flatten, and similar operations that use PDFBox directly without external CLI tools.
4.5 Unified Container — Split Frontend/Backend
The unified Dockerfile supports three operating modes via the MODE environment variable:
Mode: BOTH (default) — runs frontend and backend in a single container:
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:unified
environment:
- MODE=BOTH
- BACKEND_INTERNAL_PORT=8081
ports:
- "8080:8080"
Mode: FRONTEND — serves only the React UI, proxying API calls to a separate backend:
services:
frontend:
image: stirlingtools/stirling-pdf:unified
environment:
- MODE=FRONTEND
- VITE_API_BASE_URL=http://backend:8080
ports:
- "3000:3000"
Mode: BACKEND — runs only the Spring Boot API:
services:
backend:
image: stirlingtools/stirling-pdf:unified
environment:
- MODE=BACKEND
ports:
- "8080:8080"
volumes:
- ./configs:/configs
- ./logs:/logs
Full split deployment example:
version: "3.8"
services:
backend:
image: stirlingtools/stirling-pdf:unified
environment:
- MODE=BACKEND
- DOCKER_ENABLE_SECURITY=true
- SECURITY_ENABLELOGIN=true
ports:
- "8080:8080"
volumes:
- ./configs:/configs
- ./logs:/logs
- ./tessdata:/usr/share/tessdata
frontend:
image: stirlingtools/stirling-pdf:unified
environment:
- MODE=FRONTEND
- VITE_API_BASE_URL=http://backend:8080
ports:
- "3000:3000"
depends_on:
- backend
Important
When using
MODE=FRONTEND, theVITE_API_BASE_URLmust be set at build time or via the unified container's entrypoint script. This URL is baked into the frontend JavaScript bundle. Changing it requires a container restart.
4.6 Remote UNO Server (Scalable LibreOffice)
For high-throughput document conversion, deploy LibreOffice as remote UNO servers to distribute the load:
version: "3.8"
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest
environment:
- PROCESS_EXECUTOR_AUTO_UNO_SERVER=false
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST=uno-server-1
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PORT=2003
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_HOST_LOCATION=remote
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_0_PROTOCOL=http
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST=uno-server-2
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PORT=2003
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_HOST_LOCATION=remote
- PROCESS_EXECUTOR_UNO_SERVER_ENDPOINTS_1_PROTOCOL=http
volumes:
- shared-tmp:/tmp/stirling-pdf
ports:
- "8080:8080"
uno-server-1:
image: libreoffice-uno-server:latest
volumes:
- shared-tmp:/tmp/stirling-pdf
uno-server-2:
image: libreoffice-uno-server:latest
volumes:
- shared-tmp:/tmp/stirling-pdf
volumes:
shared-tmp:
Warning
Remote UNO servers require a shared
/tmp/stirling-pdfvolume between the Stirling-PDF container and all UNO server containers. Without this shared filesystem, file-to-pdf and other LibreOffice-dependent conversions will fail silently because the UNO server cannot access the temporary files created by Stirling-PDF.
Key configuration:
- Set
PROCESS_EXECUTOR_AUTO_UNO_SERVER=falseto disable the local UNO server - Configure each remote endpoint with incrementing index (
_0_,_1_, etc.) - Set
HOST_LOCATION=remotefor each remote endpoint - Use
PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMITto cap concurrent sessions per server
4.7 Reverse Proxy Configuration
When deploying behind a reverse proxy (Nginx, Traefik, Caddy), set SYSTEM_ROOTURIPATH to match the proxy's path prefix.
Nginx example (subpath):
location /stirling-pdf/ {
proxy_pass http://stirling-pdf:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 100M; # Match SYSTEM_MAXFILESIZE
}
With environment: SYSTEM_ROOTURIPATH=/stirling-pdf
Traefik example (subdomain):
labels:
- "traefik.enable=true"
- "traefik.http.routers.stirling.rule=Host(`pdf.example.com`)"
- "traefik.http.routers.stirling.tls.certresolver=letsencrypt"
- "traefik.http.services.stirling.loadbalancer.server.port=8080"
4.8 Health Check
The container health check endpoint:
curl -f http://localhost:8080${SYSTEM_ROOTURIPATH:-''}/api/v1/info/status | grep -q 'UP'
Docker Compose health check configuration:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/info/status"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
5. Endpoint Configuration System
The EndpointConfiguration class (in app/common) is the central mechanism for controlling which PDF operations are available at runtime. It evaluates three factors: explicit configuration, external tool availability, and group membership.
5.1 Functional Groups
Endpoints are organized into functional groups. Disabling a group disables all its member endpoints:
| Group | Endpoints | Count |
|---|---|---|
| PageOps | remove-pages, merge-pdfs, split-pages, rearrange-pages, rotate-pdf, multi-page-layout, booklet-imposition, scale-pages, crop, pdf-to-single-page, auto-split-pdf, split-by-size-or-count, overlay-pdf, split-pdf-by-sections, split-pdf-by-chapters, add-page-numbers, extract-pages | 17 |
| Convert | pdf-to-img, img-to-pdf, pdf-to-pdfa, file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-text, pdf-to-html, pdf-to-xml, html-to-pdf, url-to-pdf, markdown-to-pdf, pdf-to-csv, pdf-to-markdown, eml-to-pdf, pdf-to-epub, pdf-to-vector, vector-to-pdf, pdf-to-video, cbz-to-pdf, pdf-to-cbz, pdf-to-json, json-to-pdf, pdf-to-rtf | 24 |
| Security | add-password, remove-password, change-permissions, add-watermark, cert-sign, remove-cert-sign, sanitize-pdf, timestamp-pdf, auto-redact, validate-signature, add-stamp, unlock-pdf-forms, redact, verify-pdf, sign | 15 |
| Other | ocr-pdf, extract-images, update-metadata, flatten, remove-blanks, remove-annotations, get-info-on-pdf, add-attachments, replace-invert-pdf, edit-table-of-contents, text-editor-pdf, add-image, compare, view-pdf, multi-tool, fields, modify-fields, delete-fields, fill | 19 |
| Advance | compress-pdf, extract-image-scans, repair, auto-rename, scanner-effect, overlay-pdf, adjust-contrast | 7 |
| Automation | handleData, automate, pipeline | 3 |
| DeveloperTools | show-javascript | 1 |
| DeveloperDocs | dev-api-docs, dev-folder-scanning-docs, dev-sso-guide-docs, dev-airgapped-docs | 4 |
5.2 Tool Groups (External Dependencies)
Each tool group maps endpoints to the external binary they require:
| Tool Group | Required Binary | Dependent Endpoints |
|---|---|---|
| CLI | qpdf, Ghostscript, etc. | compress-pdf, extract-image-scans, repair, pdf-to-pdfa, file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-html, pdf-to-xml, ocr-pdf, html-to-pdf, url-to-pdf, pdf-to-rtf |
| Python | Python 3.x | extract-image-scans, html-to-pdf, url-to-pdf, file-to-pdf |
| OpenCV | OpenCV libraries | extract-image-scans |
| LibreOffice | LibreOffice (soffice) | file-to-pdf, pdf-to-word, pdf-to-presentation, pdf-to-rtf, pdf-to-html, pdf-to-xml, pdf-to-pdfa |
| Unoconvert | unoconvert | file-to-pdf (alternative to LibreOffice) |
| Java | Built-in (JVM) | 50+ endpoints — no external dependency |
5.3 Disable Reasons
When an endpoint is unavailable, the system reports one of three reasons:
| Reason | Meaning |
|---|---|
CONFIG |
Explicitly disabled via settings.yml or ENDPOINTS_GROUPS_TO_REMOVE |
DEPENDENCY |
Required external tool is not installed or not found on PATH |
UNKNOWN |
Disabled for an unidentified reason |
5.4 Endpoint Alternatives
Some endpoints support multiple backends. For example, file-to-pdf can use either LibreOffice or Unoconvert. If one tool is missing, the system falls back to the alternative if available.
5.5 Disabling Endpoints
Disable entire functional groups:
# In settings.yml
endpoints:
groupsToRemove:
- CLI
- Python
Or via environment variable:
ENDPOINTS_GROUPS_TO_REMOVE=CLI,Python
Disable all external-tool features at once:
DISABLE_ADDITIONAL_FEATURES=true
Disable individual endpoints in settings.yml:
endpoints:
disabled:
- ocr-pdf
- compress-pdf
6. Security
6.1 Authentication Modes
Stirling-PDF supports multiple authentication mechanisms, all gated behind the DOCKER_ENABLE_SECURITY=true master switch:
| Mode | Module | Configuration |
|---|---|---|
| Local login | proprietary | SECURITY_ENABLELOGIN=true — session-based username/password auth |
| OAuth2 | proprietary | Spring Security OAuth2 client configuration |
| SAML2 SSO | proprietary | Spring Security SAML 7.0.4 + OpenSAML 5.2.1 |
| API key | core/proprietary | X-API-KEY header — per-user or global (SECURITY_CUSTOMGLOBALAPIKEY) |
| MFA | proprietary | TOTP-based multi-factor authentication |
Caution
Setting
SECURITY_CUSTOMGLOBALAPIKEYcreates a single shared API key for all API access. This is convenient for automation but bypasses per-user audit trails. In production, prefer per-user API keys issued through the user management system.
6.2 CSRF Protection
Spring Security CSRF protection is enabled by default when security is active. API endpoints that accept the X-API-KEY header bypass CSRF checks (they are stateless by nature).
6.3 User & Role Management
The proprietary module provides:
- User creation, modification, deletion
- Role-based access control
- Session management (timeout, concurrent session limits)
- Audit logging of user actions
6.4 Security Hardening Checklist
[ ] Set DOCKER_ENABLE_SECURITY=true
[ ] Enable login: SECURITY_ENABLELOGIN=true
[ ] Configure OAuth2 or SAML2 for SSO
[ ] Set per-user API keys (avoid global key in production)
[ ] Enable MFA for admin accounts
[ ] Set SYSTEM_MAXFILESIZE to prevent abuse
[ ] Deploy behind reverse proxy with TLS
[ ] Set SYSTEM_GOOGLEVISIBILITY=false to prevent indexing
[ ] Mount /configs read-only if settings won't change at runtime
[ ] Review audit logs regularly
7. Operations
7.1 JVM Tuning
Two JVM profiles are available via STIRLING_JVM_PROFILE:
| Profile | GC Algorithm | Best For |
|---|---|---|
balanced (default) |
G1GC | General workloads, predictable pause times |
performance |
Shenandoah GC | Low-latency requirements, large heaps |
Additional tuning via JAVA_CUSTOM_OPTS:
# Example: increase heap for large PDF processing
JAVA_CUSTOM_OPTS="-Xmx4g -Xms2g -XX:+HeapDumpOnOutOfMemoryError"
7.2 Logging
Application logs are written to the /logs volume mount. Configure log levels via Spring Boot properties in settings.yml or environment variables.
For the AI engine, use STIRLING_LOG_LEVEL and optionally STIRLING_LOG_FILE.
7.3 Metrics
When METRICS_ENABLED=true (default), Stirling-PDF exposes Prometheus-compatible metrics. Integrate with Grafana for dashboarding:
# prometheus.yml scrape config
- job_name: 'stirling-pdf'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['stirling-pdf:8080']
7.4 Backup & Restore
Critical data to back up:
| Path | Contents | Frequency |
|---|---|---|
/configs/settings.yml |
All runtime configuration | On change |
/configs/ |
User database (if security enabled) | Daily |
/customFiles/ |
UI branding assets | On change |
/pipeline/ |
Automation pipeline definitions | On change |
/usr/share/tessdata/ |
OCR language data | On change |
7.5 Scaling Considerations
Horizontal scaling is supported via the unified container's split mode:
┌─── Frontend (MODE=FRONTEND) ──┐
Load Balancer ──────┤ ├──► Backend Pool
└─── Frontend (MODE=FRONTEND) ──┘ (MODE=BACKEND)
├── instance-1
├── instance-2
└── instance-3
Tip
LibreOffice is the primary bottleneck in high-throughput deployments. Use remote UNO servers (Section 4.6) to scale document conversion independently from the core PDF operations. Set
PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMITto prevent a single instance from being overwhelmed.
7.6 OCR Language Management
Tesseract OCR languages are installed via TESSERACT_LANGS:
# Install multiple languages
TESSERACT_LANGS=eng,fra,deu,spa,ita,por,jpn,chi_sim,chi_tra,kor,ara
# Mount custom/additional traineddata files
volumes:
- ./tessdata:/usr/share/tessdata
Language data files (.traineddata) can be downloaded from the tessdata repository and placed in the mounted volume.
8. Developer Reference
8.1 Build System
The project uses Gradle with the Spring Boot plugin:
# Build everything
./gradlew build
# Build backend only
./gradlew :app:core:build
# Run locally
./gradlew bootRun
# Run with specific profile
./gradlew bootRun --args='--spring.profiles.active=dev'
Build configuration:
- Java source/target: Java 21
- Compilation toolchain: Java 25
- Code formatter: Spotless (google-java-format 1.28.0)
- Code coverage: JaCoCo
- Static analysis: SonarQube integration
- License compliance: dependency-license-report plugin
Version sync: The syncAppVersion Gradle task synchronizes the version number across tauri.conf.json and simulation configuration files.
8.2 Frontend Build
cd frontend
# Install dependencies
npm install
# Development server
npm run dev
# Production build
npm run build
# Run tests
npm run test # Vitest unit tests
npm run test:e2e # Playwright E2E tests
8.3 AI Engine Development
cd engine
# Install dependencies
pip install -r requirements.txt
# Run locally
uvicorn stirling.api.app:app --reload --port 8000
# Run tests
pytest tests/
8.4 Code Formatting
Spotless enforces google-java-format 1.28.0:
# Check formatting
./gradlew spotlessCheck
# Auto-fix formatting
./gradlew spotlessApply
Note
The Spotless check runs as part of the build pipeline. Pull requests with formatting violations will fail CI. Run
spotlessApplybefore committing.
9. Module Reference
9.1 Backend — app/common
Shared library consumed by both core and proprietary:
| Class / Service | Purpose |
|---|---|
EndpointConfiguration |
Runtime endpoint availability management (groups, tools, alternatives) |
TaskManager |
Manages async task execution and progress tracking |
FileStorage |
Abstraction over file storage backends |
| Annotation classes | Custom annotations for endpoint metadata, validation |
| Model classes | Shared DTOs and domain models |
9.2 Backend — app/core
The core module contains all PDF operation implementations:
Controllers (app/core/src/main/java/stirling/software/SPDF/controller/api/):
19 controller files totaling ~201K characters of endpoint logic. Controllers are organized by functional domain (page operations, conversions, security, etc.) and delegate to service classes that use PDFBox for manipulation.
Configuration (app/core/.../config/):
19 configuration files handling Spring context setup, bean definitions, security filter chains, CORS, multipart file upload limits, and static resource serving.
Entry Point: stirling.software.SPDF.SPDFApplication — the @SpringBootApplication main class.
9.3 Backend — app/proprietary
Enterprise features under separate license:
| Domain | Contents |
|---|---|
| Security | OAuth2 client configuration, SAML2 service provider, SSO flow management |
| User management | User CRUD, role assignment, session management, MFA enrollment |
| Storage | Enterprise file storage backends |
| Workflows | Multi-step PDF processing workflows |
| Audit | Action logging, compliance reporting |
9.4 Frontend Services
| Service | Module | Purpose |
|---|---|---|
AutomationStorage |
core | Persist and retrieve automation/pipeline configurations |
DocumentManipulationService |
core | High-level document manipulation orchestration |
EnhancedPDFProcessingService |
core | Advanced PDF processing with progress tracking |
FileAnalyzer |
core | Analyze uploaded files (type detection, validation) |
FileProcessingService |
core | File upload, processing pipeline, result download |
FileStorageService |
core | Client-side file storage (IndexedDB) |
GoogleDrivePickerService |
core | Google Drive integration for file import |
IndexedDBManager |
core | IndexedDB wrapper for persistent browser storage |
PDFExportService |
core | Export PDFs in various formats |
PDFProcessingService |
core | Core PDF operations via PDFium WASM |
PdfiumDocument / PdfiumPage / PdfiumFont / PdfiumImage |
core | PDFium WASM bindings for client-side rendering |
PreferencesService |
core | User preference management |
ProcessingCache |
core | Cache intermediate processing results |
SignatureStorageService |
core | Store and manage digital signature data |
ThumbnailGenerationService |
core | Generate PDF page thumbnails |
UpdateService |
core | Check for application updates |
ZipFileService |
core | ZIP file creation and extraction |
UndoManager |
core | Undo/redo stack for page editor |
Page Editor Commands (command pattern):
| Command | Operation |
|---|---|
RotatePageCommand |
Rotate individual pages |
DeletePagesCommand |
Remove pages from document |
ReorderPagesCommand |
Drag-and-drop page reordering |
SplitCommand |
Split document at specified points |
9.5 Desktop Services
| Service | Purpose |
|---|---|
AuthService |
Manage authentication tokens via Tauri secure storage |
ConnectionModeService |
Switch between local, remote, and hybrid backend connections |
OperationRouter |
Route operations to local backend or remote server based on connection mode |
TauriBackendService |
Lifecycle management for the embedded backend process |
SaasBillingService |
SaaS billing integration for desktop users |
BackendHealthMonitor |
Periodic health checks on the backend, auto-restart on failure |
9.6 AI Engine Agents
| Agent | Input | Output | Use Case |
|---|---|---|---|
OrchestratorAgent |
Natural language request | Tool selection + parameters | "Convert this to Word and compress it" |
PdfEditAgent |
Edit instructions + PDF | Modified PDF | "Add a header to every page" |
PdfQuestionAgent |
Question + PDF | Natural language answer | "What is the total on page 3?" |
UserSpecAgent |
Requirements description | Specification document | Draft/revise functional specs |
ExecutionPlanningAgent |
Multi-step request | Ordered operation plan | Plan complex multi-tool workflows |
MathAuditorAgent |
Financial PDF | Audit report | Verify ledger entries, check calculations |
Supporting classes:
AppRuntime: Application lifecycle and configurationPostHogSpanProcessor: Telemetry span processing for AI agent traces
10. Supported Operations
The platform supports 38 distinct operation types (defined in engine/tool_models.py):
| Operation | Description |
|---|---|
addAttachments |
Embed files into a PDF |
addPassword |
Password-protect a PDF |
adjustContrast |
Adjust page contrast/brightness |
autoRename |
AI-based file renaming from content |
automate |
Run automation pipelines |
bookletImposition |
Arrange pages for booklet printing |
certSign |
Apply certificate-based digital signature |
changeMetadata |
Edit PDF metadata (title, author, etc.) |
changePermissions |
Set PDF permission flags |
compress |
Reduce PDF file size |
convert |
Convert between file formats |
crop |
Crop page margins |
editTableOfContents |
Modify PDF bookmarks/TOC |
extractImages |
Extract embedded images |
extractPages |
Extract specific page ranges |
flatten |
Flatten form fields and annotations |
merge |
Combine multiple PDFs |
ocr |
Optical character recognition |
overlayPdfs |
Overlay one PDF on another |
pageLayout |
Multi-page layout (N-up) |
pdfToSinglePage |
Combine all pages into one continuous page |
redact |
Permanently remove sensitive content |
removeAnnotations |
Strip all annotations |
removeBlanks |
Detect and remove blank pages |
removeCertSign |
Remove digital signatures |
removeImage |
Remove images from PDF |
removePages |
Delete specific pages |
removePassword |
Decrypt a password-protected PDF |
reorganizePages |
Reorder pages |
repair |
Repair corrupted PDFs |
replaceColor |
Replace colors in PDF content |
rotate |
Rotate pages |
sanitize |
Remove hidden data, scripts, metadata |
scalePages |
Resize pages |
scannerImageSplit |
Split scanned image pages |
sign |
Add visual signature |
split |
Split into multiple PDFs |
unlockPDFForms |
Make locked form fields editable |
watermark |
Add text/image watermark |
11. Testing
11.1 Test Infrastructure
| Test Type | Location | Framework | Command |
|---|---|---|---|
| Backend unit tests | app/core/src/test/, app/common/src/test/, app/proprietary/src/test/ |
JUnit 5 | ./gradlew test |
| Frontend unit tests | frontend/src/ |
Vitest | cd frontend && npm test |
| Frontend E2E tests | frontend/ |
Playwright | cd frontend && npm run test:e2e |
| BDD tests | testing/cucumber/ |
Cucumber | Via Gradle |
| AI engine tests | engine/tests/ |
pytest | cd engine && pytest |
| Docker CI/CD | test_cicd.yml |
Docker Compose | Compose-based integration |
| Test driver | testing/testdriver/ |
— | End-to-end test orchestration |
11.2 Translation Validation
Stirling-PDF includes automated translation quality checks:
| Validator | Purpose |
|---|---|
| TOML validator | Validates TOML translation file syntax |
| JSON structure validator | Ensures translation JSON files have consistent structure |
| Placeholder validator | Verifies {0}, {1}, etc. placeholders match across translations |
11.3 CI/CD Test Configuration
The test_cicd.yml Docker Compose file sets up a test environment with API key authentication enabled, allowing automated integration testing against a running container.
Tip
Run the full test suite before submitting PRs:
./gradlew build test spotlessCheckfor backend, andcd frontend && npm run test && npm run lintfor frontend.
12. Troubleshooting
12.1 Container Fails to Start
Error: Container exits immediately or health check fails.
Cause: Insufficient memory for JVM startup, misconfigured SYSTEM_ROOTURIPATH, or port conflict.
Solution:
- Check logs:
docker logs stirling-pdf - Verify memory: ensure at least 512 MB available
- Check port availability:
docker psfor conflicts on 8080 - If using
SYSTEM_ROOTURIPATH, ensure it starts with/and has no trailing slash
Prevention: Always configure healthcheck.start_period to at least 60 seconds to allow JVM warm-up.
12.2 LibreOffice Conversion Failures
Error: file-to-pdf, pdf-to-word, or similar endpoints return 500 errors.
Cause: LibreOffice not installed (standard/ultra-lite image), UNO server not running, or session limit exceeded.
Solution:
- Verify image type: use fat image or install LibreOffice manually
- Check UNO server:
docker exec stirling-pdf ps aux | grep soffice - If remote UNO: verify shared
/tmp/stirling-pdfvolume and network connectivity - Increase session limit:
PROCESS_EXECUTOR_SESSION_LIMIT_LIBRE_OFFICE_SESSION_LIMIT=4
Prevention: Use the fat Docker image for deployments requiring document conversion.
12.3 OCR Returns Empty Text
Error: ocr-pdf endpoint produces a PDF with no recognized text.
Cause: Missing Tesseract language data for the document's language.
Solution:
- Install required language:
TESSERACT_LANGS=eng,fra,deu(rebuild container) - Or mount traineddata files:
-v ./tessdata:/usr/share/tessdata - Verify language availability inside container:
ls /usr/share/tessdata/
Prevention: Pre-install all expected languages via TESSERACT_LANGS.
12.4 Large File Upload Fails
Error: 413 Request Entity Too Large or upload timeout.
Cause: SYSTEM_MAXFILESIZE too low, or reverse proxy body size limit.
Solution:
- Increase
SYSTEM_MAXFILESIZE(in MB) - Match reverse proxy limit:
client_max_body_size 500M;in Nginx - Increase proxy timeout for large files
Prevention: Set consistent limits across Stirling-PDF config and reverse proxy.
12.5 Endpoints Show as Disabled
Error: UI shows certain operations as unavailable.
Cause: Missing external tool dependency, or group disabled via configuration.
Solution:
- Check endpoint status via API:
GET /api/v1/info/status - Review disable reason (CONFIG vs DEPENDENCY)
- For DEPENDENCY: install the required tool or switch to fat image
- For CONFIG: review
settings.ymlandENDPOINTS_GROUPS_TO_REMOVE
Prevention: Use the fat Docker image to ensure all dependencies are present.
12.6 Split Frontend Cannot Reach Backend
Error: Frontend shows connection errors or blank pages.
Cause: VITE_API_BASE_URL not set or set to unreachable address.
Solution:
- Verify
VITE_API_BASE_URLpoints to the backend's actual URL - Ensure backend is running and healthy
- Check network connectivity between frontend and backend containers
- Verify CORS configuration if frontend and backend are on different domains
Prevention: Use Docker Compose networking (service names) for container-to-container communication.
Caution
When running in split mode, the backend URL must be accessible from both the frontend container (for SSR/proxying) and the end user's browser (for client-side API calls). Ensure the URL is publicly reachable or configure appropriate proxy rules.
12.7 Database Import Constraint Error
Error: Database import fails with constraint violation (relates to GitHub issue #4405).
Cause: Schema migration conflict or duplicate key in imported data.
Solution:
- Back up existing database before import
- Verify the import file matches the current schema version
- If upgrading from an older version, let the application run its migrations first, then import
Prevention: Always export/import databases between matching application versions.
12.8 Windows SmartScreen Blocks Desktop Installer
Error: Windows SmartScreen prevents the desktop installer from running (GitHub issue #5600).
Cause: The executable is not yet widely distributed enough to build SmartScreen reputation, or code signing certificate is not recognized.
Solution:
- Click "More info" then "Run anyway" in the SmartScreen dialog
- Alternatively, right-click the installer, go to Properties, and check "Unblock"
- For enterprise deployment, add the installer hash to your organization's allow list via Group Policy
Prevention: Enterprise administrators should pre-approve the installer via WDAC or AppLocker policies.
13. API Reference
13.1 Authentication
API requests can be authenticated via:
# Per-user API key
curl -H "X-API-KEY: your-api-key" http://localhost:8080/api/v1/info/status
# Global API key (if SECURITY_CUSTOMGLOBALAPIKEY is set)
curl -H "X-API-KEY: global-key" http://localhost:8080/api/v1/info/status
13.2 Core Endpoints
The API exposes endpoints matching the 38 operation types listed in Section 10. Each operation accepts multipart form data with the PDF file and operation-specific parameters.
General pattern:
# Example: Merge PDFs
curl -X POST http://localhost:8080/api/v1/general/merge-pdfs \
-H "X-API-KEY: your-key" \
-F "fileInput=@file1.pdf" \
-F "fileInput=@file2.pdf"
# Example: Compress PDF
curl -X POST http://localhost:8080/api/v1/general/compress-pdf \
-H "X-API-KEY: your-key" \
-F "fileInput=@document.pdf" \
-F "optimizeLevel=3"
# Example: OCR
curl -X POST http://localhost:8080/api/v1/misc/ocr-pdf \
-H "X-API-KEY: your-key" \
-F "fileInput=@scanned.pdf" \
-F "languages=eng"
13.3 Info Endpoints
# Health/status check
GET /api/v1/info/status
# Application information
GET /api/v1/info
13.4 AI Engine Endpoints
When the AI engine is running:
# Orchestrate a natural language request
POST /orchestrate
# Ask questions about a PDF
POST /pdf_questions
# AI-guided PDF editing
POST /pdf_edit
# Draft a specification
POST /draft
# Revise a specification
POST /revise
# Get next action recommendation
POST /next-action
# Examine a document
POST /examine
# Deliberate on a complex request
POST /deliberate
# Health check
GET /health
14. Integration Points
14.1 PostHog Analytics
Both the frontend (SaaS module) and the AI engine support PostHog telemetry:
- AI Engine: Set
STIRLING_POSTHOG_ENABLED=true,STIRLING_POSTHOG_API_KEY, andSTIRLING_POSTHOG_HOST - Frontend SaaS: PostHog is integrated in the SaaS deployment module for user behavior analytics
14.2 Google Drive
The GoogleDrivePickerService in the frontend core enables importing files directly from Google Drive into Stirling-PDF operations.
14.3 Stripe Billing
The proprietary frontend module includes Stripe checkout integration for SaaS billing scenarios.
14.4 Windows Shell Integration
The Windows thumbnail handler DLL (stirling_thumbnail_handler.dll) registers as a COM IThumbnailProvider for the .pdf file extension, providing native PDF thumbnails in Windows Explorer when the desktop app is installed.
14.5 Enterprise Provisioner
The Tauri provisioner tool allows enterprise IT to preconfigure desktop installations:
- Lock the server URL to a specific Stirling-PDF instance
- Prevent users from switching connection modes
- Deploy via standard MSI/MSIX enterprise deployment tools
15. Known Issues
| Issue | Status | Description |
|---|---|---|
| #1612 | Open | Split PDF operation removes input fields from the resulting documents |
| #4405 | Open | Database import fails with constraint violation errors |
| #5951 | Open | Docker image crash under certain conditions |
| #6120 | Open | False positive virus detection on v2.9.2 binaries |
| #5600 | Open | Windows SmartScreen blocks the desktop installer |
| #6123 | Open | French translation issues in certain UI strings |
Warning
Issue #6120 (false positive virus detection) affects v2.9.2 specifically. If your security software flags the Docker image or desktop binary, verify the checksum against the official release and add an exception if it matches.
16. Quick Reference
16.1 Minimal Docker Run
docker run -d -p 8080:8080 stirlingtools/stirling-pdf:latest
16.2 Production Docker Compose
version: "3.8"
services:
stirling-pdf:
image: stirlingtools/stirling-pdf:latest-fat
ports:
- "8080:8080"
volumes:
- ./configs:/configs
- ./logs:/logs
- ./tessdata:/usr/share/tessdata
- ./customFiles:/customFiles
- ./pipeline:/pipeline
environment:
- DOCKER_ENABLE_SECURITY=true
- SECURITY_ENABLELOGIN=true
- FAT_DOCKER=true
- SYSTEM_MAXFILESIZE=200
- SYSTEM_DEFAULTLOCALE=en-US
- TESSERACT_LANGS=eng,fra,deu,spa
- METRICS_ENABLED=true
- STIRLING_JVM_PROFILE=balanced
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/info/status"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
16.3 Key Paths Inside Container
| Path | Purpose |
|---|---|
/configs/settings.yml |
Primary configuration |
/logs/ |
Application logs |
/usr/share/tessdata/ |
OCR language data |
/customFiles/ |
UI customization |
/pipeline/ |
Automation pipelines |
/tmp/stirling-pdf/ |
Temporary files (shared for remote UNO) |
16.4 Contributing Checklist
./gradlew spotlessApply # Format Java code
./gradlew test # Run backend tests
cd frontend && npm test # Run frontend tests
./gradlew build # Full build verification