---
title: "How it works"
description: "The CloudPDF server architecture — the HTTP API, the native worker pool, the storage and database layers, and how a request flows through them."
source: "https://www.cloudpdf.com/docs/server/getting-started/how-it-works"
---

# How it works

The server is a single Node process with three responsibilities: speak HTTP,
render PDFs, and persist documents. Understanding the pieces makes every
configuration choice obvious.

## The big picture

```
        ┌──────────────┐        Bearer JWT        ┌───────────────────────────┐
        │ Your frontend│ ───────────────────────▶ │     @cloudpdf/server      │
        │ @cloudpdf/   │                           │                           │
        │   engine     │ ◀─────────────────────── │  Fastify HTTP API         │
        └──────────────┘   pages, text, metadata   │      │                    │
                                                    │      ▼                    │
        ┌──────────────┐   mints doc-scoped JWT     │  Worker pool (PDFium)     │
        │ Your backend │ ─────────────────────────▶│      │                    │
        └──────────────┘                            │      ▼                    │
                                                    │  Database   Object store  │
                                                    └───────┼──────────┼────────┘
                                                            ▼          ▼
                                                   SQLite/Postgres  disk / S3 /
                                                                    GCS / Azure
```

1. **Your backend mints a token.** When a user needs a document, your backend
   issues a short-lived, document-scoped JWT signed with the shared
   `CLOUDPDF_JWT_SECRET`.
2. **The frontend calls the server** with that token via
   [`@cloudpdf/engine`](https://www.cloudpdf.com/docs/engine). The token says *which* document and
   *what* the caller may do.
3. **The server verifies the token, loads the document** from the object store
   (caching it locally), and hands the work to a native PDFium worker.
4. **Results come back as JSON or images** — rendered pages, extracted text,
   annotations, metadata.

## The HTTP API

A [Fastify](https://fastify.dev) server exposes two route families:

| Routes                | Auth                | Purpose                                                                                                                        |
| --------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `/v1/docs/*`          | Document-scoped JWT | Render pages, extract text, read/write annotations and metadata, unlock encrypted PDFs. This is what `@cloudpdf/engine` calls. |
| `/v1/admin/*`         | Admin JWT           | Create documents, upload files, mint and revoke tokens. This is what your backend calls.                                       |
| `/healthz`, `/readyz` | None                | Liveness and readiness probes.                                                                                                 |

Every document and admin route requires a valid token; an unauthenticated call
returns `401`. See [Authentication](https://www.cloudpdf.com/docs/server/configuration/authentication)
for how tokens are scoped.

## The native worker pool

PDFium is a native C++ library. The server runs it inside a pool of Node
`worker_thread`s so that CPU-heavy rendering never blocks the HTTP event loop and
several requests can render in parallel.

The pool size is controlled by
[`CLOUDPDF_WORKER_POOL_SIZE`](https://www.cloudpdf.com/docs/server/operations/health-and-scaling). The
default is conservative — `min(2, cpu count)` — and you raise it as you give the
process more cores and memory.

> Native code parsing hostile PDFs will eventually crash. Two layers keep that
> survivable: set `CLOUDPDF_ENGINE_ISOLATION=host` so a crash costs
> a **sub-second engine respawn** inside the instance (documents
> that repeatedly crash the engine are quarantined automatically), and run
> **multiple replicas** so even an instance restart never means
> zero capacity. See
> [Health & scaling](https://www.cloudpdf.com/docs/server/operations/health-and-scaling).

## Storage: database + object store

The server separates **metadata** from **bytes**:

- **Database** — document records, annotations, tokens, and the audit log. Use
  **SQLite** (a single file, zero setup) to start, or **Postgres** for
  multi-replica production. See [Database](https://www.cloudpdf.com/docs/server/configuration/database).
- **Object store** — the actual PDF bytes and rendered artifacts. Use the
  **local filesystem** for a single host, or **S3 / GCS / Azure Blob** for
  durable, shared storage. See [Storage](https://www.cloudpdf.com/docs/server/configuration/storage).
- **Cache** — a local directory of recently used documents and renders so repeat
  requests are fast. It is disposable; the server rebuilds it from the object
  store.

This split is what lets the same binary run as a zero-config single file *and* as
a horizontally-scaled cluster — you only change configuration.

> The smallest possible setup — SQLite + local disk + local cache — needs
> **no external services at all**. That is exactly what the
> [Quick start](https://www.cloudpdf.com/docs/server/getting-started/quick-start) uses.

## Twelve-factor by design

Everything is configured through `CLOUDPDF_*` environment variables, the
process logs to stdout, and state lives in the database, object store, and
cache — never in the container. That is what makes the same image safe to run as
one container or fifty pods.

## Next steps

- [Quick start](https://www.cloudpdf.com/docs/server/getting-started/quick-start) — Get a server running and make your first request.
- [Choosing a deployment](https://www.cloudpdf.com/docs/server/deployment) — npm, Docker, Compose, or Helm — and when to use each.
