\usepackage{golang}
Compile LaTeX to PDF from Go using the FormaTeX REST API. Standard net/http — no external binary, no TeX Live installation required.
\section{Why Go}
Forget bundling TeX Live in your Docker image. FormaTeX handles compilation server-side — your Go binary stays lean.
The FormaTeX API is a plain HTTP endpoint. Use the standard library — no special SDK, no new dependency in your go.mod.
Use goroutines and sync.WaitGroup to compile multiple documents in parallel. The API handles concurrent requests without rate-limiting goroutines.
\section{Quick Start}
The example below compiles a minimal LaTeX document and writes the resulting PDF to disk. Replace your-api-key with a key from your dashboard. In production, read it from os.Getenv("FORMATEX_API_KEY").
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
const (
apiKey = "your-api-key" // use os.Getenv in production
apiURL = "https://api.formatex.io/v1"
)
func main() {
latex := `\documentclass{article}
\usepackage{amsmath}
\begin{document}
Hello from Go! $E = mc^2$
\end{document}`
pdf, err := compileLaTeX(latex, "pdflatex")
if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
if err := os.WriteFile("output.pdf", pdf, 0644); err != nil {
fmt.Fprintf(os.Stderr, "write error: %v\n", err)
os.Exit(1)
}
fmt.Println("PDF saved to output.pdf")
}
func compileLaTeX(source, engine string) ([]byte, error) {
body, _ := json.Marshal(map[string]string{
"source": source,
"engine": engine,
})
req, _ := http.NewRequest("POST", apiURL+"/compile/sync", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errBody, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API error %d: %s", resp.StatusCode, errBody)
}
return io.ReadAll(resp.Body)
}\section{HTTP Handler}
Drop this handler into your net/http server. It accepts a JSON body with source and engine fields, proxies the request to FormaTeX, and streams the PDF response directly to the client.
package main
import (
"bytes"
"encoding/json"
"io"
"net/http"
"os"
)
func generatePDFHandler(w http.ResponseWriter, r *http.Request) {
var req struct {
Source string `json:"source"`
Engine string `json:"engine"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid request", http.StatusBadRequest)
return
}
if req.Engine == "" {
req.Engine = "pdflatex"
}
body, _ := json.Marshal(req)
apiReq, _ := http.NewRequest("POST",
"https://api.formatex.io/v1/compile/sync",
bytes.NewReader(body),
)
apiReq.Header.Set("Authorization", "Bearer "+os.Getenv("FORMATEX_API_KEY"))
apiReq.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(apiReq)
if err != nil {
http.Error(w, "upstream error", http.StatusBadGateway)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
w.WriteHeader(http.StatusInternalServerError)
io.Copy(w, resp.Body)
return
}
w.Header().Set("Content-Type", "application/pdf")
w.Header().Set("Content-Disposition", "attachment; filename=output.pdf")
io.Copy(w, resp.Body)
}\section{Authentication}
Store your API key in the environment — never hardcode it in source files:
apiKey := os.Getenv("FORMATEX_API_KEY")
FORMATEX_API_KEY in your shell, Docker environment, or secrets manager.Authorization: Bearer <key>.\section{Concurrency}
Use goroutines and sync.WaitGroup to compile multiple documents in parallel. Each goroutine makes an independent HTTP request — Go's concurrency model maps naturally onto the FormaTeX REST API.
For large batches, use the async compile endpoint which returns a job ID you can poll — ideal when you need to compile hundreds of documents without holding open HTTP connections.
\section{Reference}
| Field | Type | Required | Description |
|---|---|---|---|
| source | string | Yes | Full LaTeX source code as a string |
| engine | string | No | Engine to use. Default: "pdflatex". Options: pdflatex, xelatex, lualatex, latexmk |
POST https://api.formatex.io/v1/compile/sync — Returns raw PDF bytes on success (200), or JSON error on failure (422/401).
\section{Error Handling}
The API returns HTTP status codes. Check resp.StatusCode before reading the body:
200 — raw PDF bytes. Read with io.ReadAll(resp.Body).422 — LaTeX compilation error. JSON body contains an error field with the TeX log excerpt.401 — invalid or missing API key.\end{golang}
Get your API key and have PDF output from Go in minutes — no TeX Live 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.