pdfx CLI: Local First, Cloud When You Need It
pdfx processes PDFs on your machine by default. Opt into cloud mode with an API base and key when you need hosted or self-hosted PDF123 REST endpoints.

PDF123 is the product name. pdfx is the short CLI that talks to the same operations. The default path is local: read a file, run the op through pdf-core, write an output. No account, no API key, no upload.
Local first means the file never leaves
A typical call looks like pdfx merge a.pdf b.pdf -o merged.pdf or pdfx compress input.pdf. Processing runs where the binary runs. That fits CI jobs on a private runner, scripts next to a batch of invoices, and any case where uploading to a third party is the wrong answer.
Local mode is not a thin wrapper that secretly posts bytes elsewhere. The CLI shares the same operation registry as the server (pdf_core::ops::run). If you want the network path, you opt in with --cloud.
Built-in subcommands cover common ops: merge, split, compress, rotate, extract, OCR, convert, protect, unlock, watermark, and related work. Local output defaults to a file via -o / --output; - writes to stdout.
--cloud is the same catalog over HTTP
When you need the hosted API (or your own pdfx-server), pass --cloud with --api-base and --api-key (or PDFX_API_KEY). Cloud mode requires curl under the hood and fails if no API key is set. Example from the published skill:
pdfx --cloud --api-base "$PDFX_API_BASE" --api-key "$PDFX_API_KEY" \
merge a.pdf b.pdf -o merged.pdf
--api-base defaults to https://pdf123.xyz, the hosted API. For a local Docker Compose stack, point it at http://127.0.0.1:8080 instead. The CLI becomes a client of the REST surface documented on Developers; op names line up with the portal tools and OpenAPI (/v1/openapi.json).
Cloud mode does not change what an op means. Compress is still qpdf stream compression; OCR still returns Markdown text from the Rust path, not a searchable PDF layer. Leftover CLI flags that map to ignored Java-era OCR params (for example a languages field) do not change that contract.
Why two modes exist
Local covers offline trust and zero round-trip cost. Cloud covers shared rate limits, running ops on a machine that only has the CLI and curl installed, and teams that already issue API keys. Agents can also call the same base via MCP at /mcp or the skill at dist/skills/pdf-toolbox/SKILL.md. Discovery indexes such as /llms.txt help coding agents find endpoints; they are not a Google ranking signal.
For safe retries of mutating POSTs against the API, send Idempotency-Key (see Idempotency-Key: Safe Retries for PDF Jobs). The CLI's cloud path is still one HTTP request per invocation; use the header when your wrapper retries.
Picking a mode in practice
Use local when the files must stay on the runner, when you already have the pdfx binary and native deps on that machine, and when latency is dominated by the op rather than upload. Use cloud when the heavy deps live only on the server, when you want the same rate limits and metering as other API clients, or when agents already hold an API key for https://pdf123.xyz or your self-hosted base.
Do not mix expectations: local OCR still follows the Markdown output contract of misc/ocr-pdf; cloud compress is still qpdf streams, not font-subsetting. The mode switch changes where the op runs, not the semantics of the catalog.
What the CLI is not
pdfx is not a desktop GUI and not an embeddable OCR library you link into another app. It is a command-line client for PDF operations: local by default, HTTP when you ask. Browser one-offs still live on the portal (Compress, OCR, and the rest of the catalog). Automation that prefers a binary can stay on pdfx.
Same-op comparisons across browser, curl, MCP, and CLI are sketched in Same operation, four clients. Start from Developers for keys and OpenAPI, or Self-host if the API base should be your own Docker Compose stack.