Generating a PDF involves a round-trip to a Chrome process and can take hundreds of milliseconds. SferaDoc provides two independent, opt-in caching layers.
Render Pipeline
On each SferaDoc.render/3 call:
- Hot cache — check Redis/ETS for a cached PDF binary → return if found
- Object store — check durable storage (S3/Azure/FileSystem) → return if found (and backfill hot cache)
- Generate — render the template to HTML, convert to PDF via ChromicPDF, persist to both stores
Both layers are optional and independent of each other.
Hot Cache
Ephemeral cache for fast repeated reads. Backed by Redis or ETS.
Redis Hot Cache
config :sfera_doc, :pdf_hot_cache,
adapter: :redis,
ttl: 60 # seconds
config :sfera_doc, :redis,
host: "localhost",
port: 6379
ETS Hot Cache
config :sfera_doc, :pdf_hot_cache,
adapter: :ets,
ttl: 60 # seconds
Memory warning: PDFs can be 100 KB – 10 MB or more. Only enable this cache with an explicit TTL. For Redis, configure a
maxmemory-policy(e.g.allkeys-lru). For ETS, ensure your BEAM VM has enough memory.
Object Store
Durable PDF storage, surviving restarts and deployments. Three adapters are included.
Amazon S3
Requires ex_aws and ex_aws_s3:
{:ex_aws, "~> 2.5"},
{:ex_aws_s3, "~> 2.5"},
config :sfera_doc, :pdf_object_store,
adapter: SferaDoc.PdfEngine.ObjectStore.S3,
bucket: "my-pdf-bucket",
prefix: "pdfs/" # optional key prefix
AWS credentials are read from the standard ExAws sources (environment variables, instance profile, etc.).
Azure Blob Storage
Requires azurex:
{:azurex, "~> 1.1"},
config :sfera_doc, :pdf_object_store,
adapter: SferaDoc.PdfEngine.ObjectStore.Azure,
container: "pdfs"
Local Filesystem
No extra dependencies:
config :sfera_doc, :pdf_object_store,
adapter: SferaDoc.PdfEngine.ObjectStore.FileSystem,
path: "/var/app/pdfs"
Custom Object Store Adapter
Implement the SferaDoc.PdfEngine.ObjectStore.Adapter behaviour:
defmodule MyApp.CustomObjectStore do
@behaviour SferaDoc.PdfEngine.ObjectStore.Adapter
@impl true
def get(key), do: ... # {:ok, binary} | {:error, :not_found} | {:error, term}
@impl true
def put(key, binary), do: ... # :ok | {:error, term}
end
Using Both Layers
Hot cache and object store can be active simultaneously:
config :sfera_doc, :pdf_hot_cache,
adapter: :redis,
ttl: 300
config :sfera_doc, :pdf_object_store,
adapter: SferaDoc.PdfEngine.ObjectStore.S3,
bucket: "my-pdf-bucket"
The pipeline will:
- Return from Redis if present (fastest)
- Return from S3 if present (and backfill Redis)
- Generate fresh, write to S3, write to Redis