FormaTeX

\usepackage{golang}

Go LaTeX to PDF API

Compile LaTeX to PDF from Go using the FormaTeX REST API. Standard net/http — no external binary, no TeX Live installation required.

Also available in:Python·Node.js·Go·PHP·Ruby·Rust·cURL|Full API reference

\section{Why Go}

Why Go + FormaTeX

No external binary needed

Forget bundling TeX Live in your Docker image. FormaTeX handles compilation server-side — your Go binary stays lean.

net/http native

The FormaTeX API is a plain HTTP endpoint. Use the standard library — no special SDK, no new dependency in your go.mod.

Concurrent compilation

Use goroutines and sync.WaitGroup to compile multiple documents in parallel. The API handles concurrent requests without rate-limiting goroutines.

\section{Quick Start}

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").

main.go
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}

HTTP handler example

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.

handler.go
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}

Environment variables

Store your API key in the environment — never hardcode it in source files:

apiKey := os.Getenv("FORMATEX_API_KEY")
  • Generate API keys from your dashboard after signing up.
  • Set FORMATEX_API_KEY in your shell, Docker environment, or secrets manager.
  • All requests must include Authorization: Bearer <key>.

\section{Concurrency}

Concurrent compilation

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}

API reference

FieldTypeRequiredDescription
sourcestringYesFull LaTeX source code as a string
enginestringNoEngine to use. Default: "pdflatex". Options: pdflatex, xelatex, lualatex, latexmk

POST https://api.formatex.io/v1/compile/syncReturns raw PDF bytes on success (200), or JSON error on failure (422/401).

\section{Error Handling}

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}

Start compiling LaTeX from Go

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.

Cookie policy