FormaTeX

\usepackage{docker}

LaTeX in Docker without TeX Live

4 GB TeX Live installation? Not in your Docker image. Use the FormaTeX API to compile LaTeX to PDF from any container — Alpine, Debian, Node, whatever your stack runs on.

\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.

docker run -e FORMATEX_API_KEY=$FORMATEX_API_KEY my-latex-image

.env file

Store the key in a .env file (never committed to version control) and reference it with --env-file.

docker run --env-file .env my-latex-image

Docker secrets

For production Swarm or Compose deployments, use Docker secrets so the key is never exposed as a plain environment variable.

docker secret create formatex_api_key ./key.txt

\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.

Shrink your Docker image today

Free tier — 15 API compilations per month. No credit card required.

One quick thing

We track anonymous usage — page views, feature usage, compilation events — to understand what works and what doesn't. No ads, no personal data, no third-party sharing.

Cookie policy