\section{Why FormaTeX in Docker}
Smaller images, cleaner builds
Bundling TeX Live in a Docker image adds gigabytes and minutes to your build. FormaTeX handles compilation remotely — your container stays lean.
Save ~4 GB image size
TeX Live full weighs over 4 GB. With FormaTeX, your Dockerfile adds only curl and jq — a few megabytes total.
Consistent output everywhere
Every build runs against the same FormaTeX engine version. No more 'works on my machine' PDF differences between dev and CI.
No permission issues
TeX Live requires write access to package directories. API-based compilation eliminates filesystem permission headaches in rootless containers.
\section{Minimal Dockerfile}
A Dockerfile with no TeX Live
Start from alpine:latest, install curl and jq, copy the compile script, and you're done. The entire image is under 20 MB.
# No TeX Live needed — just curl and the FormaTeX API
FROM alpine:latest
RUN apk add --no-cache curl jq
WORKDIR /app
COPY compile.sh .
RUN chmod +x compile.sh
CMD ["./compile.sh"]\section{compile.sh}
The compile script
This POSIX shell script validates the environment, reads the source file, and POSTs it to the FormaTeX API via jq for safe JSON encoding. The engine and paths are configurable via arguments and environment variables.
#!/bin/sh
# compile.sh — compile main.tex to output.pdf via FormaTeX API
set -e
if [ -z "$FORMATEX_API_KEY" ]; then
echo "Error: FORMATEX_API_KEY environment variable not set"
exit 1
fi
TEX_FILE="${1:-main.tex}"
OUTPUT="${2:-output.pdf}"
ENGINE="${ENGINE:-pdflatex}"
echo "Compiling $TEX_FILE with $ENGINE..."
curl -X POST https://api.formatex.io/v1/compile/sync \
-H "Authorization: Bearer $FORMATEX_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile src "$TEX_FILE" \
--arg engine "$ENGINE" \
'{"source": $src, "engine": $engine}')" \
--output "$OUTPUT"
echo "PDF saved to $OUTPUT"\section{docker-compose}
Compose with your application
Mount a local directory as a volume so the compiler reads your .tex files and writes PDFs back to disk. The FORMATEX_API_KEY is injected from the host environment — never baked into the image.
version: '3.8'
services:
latex-compiler:
build: .
environment:
- FORMATEX_API_KEY=${FORMATEX_API_KEY}
- ENGINE=pdflatex
volumes:
- ./documents:/app/documents
command: ["./compile.sh", "documents/thesis.tex", "documents/thesis.pdf"]
# Or as part of a larger application
app:
image: your-app:latest
environment:
- FORMATEX_API_KEY=${FORMATEX_API_KEY}
depends_on:
- latex-compiler\section{Multi-stage build}
Build app and PDFs in one pipeline
This multi-stage Dockerfile builds a Node.js app, compiles all .tex report templates via FormaTeX, and assembles the final image with pre-compiled PDFs already in public/reports/. Pass FORMATEX_API_KEY as a build argument — it is never embedded in the final layer.
# Multi-stage: build your app and compile LaTeX in one pipeline
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm install
COPY . .
RUN npm run build
FROM alpine:latest AS pdf-compiler
RUN apk add --no-cache curl jq
WORKDIR /pdfs
COPY --from=builder /app/reports ./reports
ARG FORMATEX_API_KEY
RUN for tex_file in reports/*.tex; do \
base=$(basename "$tex_file" .tex); \
curl -X POST https://api.formatex.io/v1/compile/sync \
-H "Authorization: Bearer $FORMATEX_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile src "$tex_file" '{"source": $src, "engine": "pdflatex"}')" \
--output "reports/$base.pdf"; \
done
FROM node:20-alpine AS runner
COPY --from=builder /app/.next ./.next
COPY --from=pdf-compiler /pdfs/reports ./public/reports\section{Environment variables}
Passing the API key safely
docker run -e
Pass the key inline at runtime. The value comes from your shell environment, not the image.
.env file
Store the key in a .env file (never committed to version control) and reference it with --env-file.
Docker secrets
For production Swarm or Compose deployments, use Docker secrets so the key is never exposed as a plain environment variable.
\section{Troubleshooting}
Common issues and solutions
jq not found in image
The compile.sh script uses jq to safely encode the LaTeX source as JSON. On Alpine, add it with apk add --no-cache curl jq. On Debian/Ubuntu, use apt-get install -y curl jq. Without jq, special characters in your .tex file will break the JSON payload.
File path issues with volumes
When mounting volumes, the path inside the container must match what the script receives. If you mount ./documents to /app/documents, call the script as ./compile.sh documents/thesis.tex. Use absolute paths inside the container to avoid ambiguity.
Rate limiting on bulk builds
The free tier allows 15 API compilations per month. If your multi-stage build compiles many files, add a short sleep between requests or upgrade to a paid plan with higher rate limits. The API returns HTTP 429 when the limit is reached.
\section{Related integrations}
Use FormaTeX from any environment
The same API call works in any CI runner, cloud function, or local script.

