\begin{article}
Multi-File LaTeX Documents via API
Compile LaTeX projects with includes, bibliography files, and custom classes via the FormatEx API — no zip required, just structured JSON payloads.

Most LaTeX tutorials treat a document as a single .tex file. Real projects are not. An academic paper has a bibliography. A thesis has chapter files split across directories. A journal submission requires a custom .cls file you cannot strip out. If you have ever tried to compile a multi-file LaTeX project through a naive API, you know the result: File not found errors, missing references, and an incomplete PDF. FormatEx handles multi-file LaTeX API compilation natively — you send every file your document needs as a structured JSON payload, and the API compiles them together exactly as latexmk would on your local machine.
This tutorial walks through the complete workflow: structuring your payload, handling \input and \include, attaching bibliography files, bundling custom classes, and picking the right engine for each use case.
How Multi-File Compilation Works in FormatEx
The FormatEx compile endpoint accepts a files array alongside your main document content. Each entry in the array describes one file: its path relative to the compilation root and its content as a UTF-8 string. The API writes all files to an ephemeral workspace, then runs your chosen engine against the main entry point.
POST https://api.formatex.io/api/v1/compile
X-API-Key: fex_your_key_here
Content-Type: application/jsonThe request body shape for a multi-file job:
{
"engine": "latexmk",
"main": "main.tex",
"files": [
{
"path": "main.tex",
"content": "..."
},
{
"path": "sections/introduction.tex",
"content": "..."
},
{
"path": "references.bib",
"content": "..."
},
{
"path": "custom.cls",
"content": "..."
}
]
}The main field tells the API which file is the entry point. Everything else in files is available to that document via its relative path. Subdirectories are created automatically — you do not need to declare them separately.
Structuring an Academic Paper Payload
Consider a realistic conference paper layout:
main.tex
abstract.tex
sections/
introduction.tex
related-work.tex
methodology.tex
results.tex
conclusion.tex
figures/
architecture.pdf
acm-style.cls
references.bibHere is how you send this to the FormatEx API in TypeScript using the native fetch API:
import fs from "fs";
const API_URL = "https://api.formatex.io/api/v1/compile";
const API_KEY = process.env.FORMATEX_API_KEY!;
function readFile(filePath: string): { path: string; content: string } {
return {
path: filePath,
content: fs.readFileSync(filePath, "utf-8"),
};
}
async function compileAcademicPaper(): Promise<Buffer> {
const files = [
readFile("main.tex"),
readFile("abstract.tex"),
readFile("sections/introduction.tex"),
readFile("sections/related-work.tex"),
readFile("sections/methodology.tex"),
readFile("sections/results.tex"),
readFile("sections/conclusion.tex"),
readFile("acm-style.cls"),
readFile("references.bib"),
// Binary assets like PDFs must be base64-encoded
{
path: "figures/architecture.pdf",
content: fs.readFileSync("figures/architecture.pdf").toString("base64"),
encoding: "base64",
},
];
const response = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
engine: "latexmk",
main: "main.tex",
files,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Compilation failed: ${error.error}`);
}
return Buffer.from(await response.arrayBuffer());
}
compileAcademicPaper()
.then((pdf) => fs.writeFileSync("output.pdf", pdf))
.then(() => console.log("PDF written to output.pdf"))
.catch(console.error);The main.tex entry point uses standard \input and \include commands exactly as you would locally:
\documentclass{acm-style}
\usepackage[backend=biber,style=acmnumeric]{biblatex}
\addbibresource{references.bib}
\begin{document}
\maketitle
\input{abstract}
\include{sections/introduction}
\include{sections/related-work}
\include{sections/methodology}
\include{sections/results}
\include{sections/conclusion}
\printbibliography
\end{document}No changes to your LaTeX source are needed. The API resolves paths relative to the compilation root, so \include{sections/introduction} maps directly to the file at sections/introduction.tex in your payload. For a deeper look at automating this kind of workflow, see automating academic paper PDFs with the LaTeX API.
Choosing the Right Engine for Bibliography Passes
Bibliography compilation is where single-pass engines fail. If you use \bibliography with BibTeX or \addbibresource with BibLaTeX, you need multiple compiler passes to resolve citations and generate the reference list.
| Engine | Bibliography support | Passes | Use case |
|---|---|---|---|
pdflatex | Manual (requires bibtex/biber separately) | 1 | Simple documents, no bibliography |
xelatex | Same as pdflatex | 1 | Unicode fonts, no bibliography |
lualatex | Same as pdflatex | 1 | Lua scripting, complex fonts |
latexmk | Automatic (runs biber/bibtex as needed) | 2—4 | Academic papers, bibliographies, cross-references |
For any document using \cite, \ref, \label, or a bibliography, use latexmk. It detects what auxiliary tools are needed, runs them in the correct order, and re-runs the main compiler until all references are resolved. Sending a BibTeX document to pdflatex through the API will produce a PDF with [?] placeholders instead of citations. For a full breakdown of pdfLaTeX vs XeLaTeX vs LuaLaTeX trade-offs, the engine guide covers each engine's strengths in detail.
The engine choice is a single field change in your request body:
{
"engine": "latexmk",
"main": "main.tex",
"files": [...]
}Using Custom Document Classes and Style Files
Many journals and conferences distribute their own .cls or .sty files and require submissions to use them. The FormatEx API treats these exactly like any other file — include them in the files array at the path your \documentclass or \usepackage command expects.
A common pattern is to collect all supplementary class files into a directory and reference them with a directory walker:
import os
import requests
def load_files_from_directory(directory: str) -> list[dict]:
files = []
for root, _, filenames in os.walk(directory):
for filename in filenames:
full_path = os.path.join(root, filename)
rel_path = os.path.relpath(full_path, directory)
rel_path = rel_path.replace("\\", "/")
with open(full_path, "r", encoding="utf-8") as f:
files.append({"path": rel_path, "content": f.read()})
return files
def compile_with_custom_class(project_dir: str) -> bytes:
files = load_files_from_directory(project_dir)
response = requests.post(
"https://api.formatex.io/api/v1/compile",
headers={
"X-API-Key": os.environ["FORMATEX_API_KEY"],
"Content-Type": "application/json",
},
json={
"engine": "latexmk",
"main": "main.tex",
"files": files,
},
timeout=120,
)
response.raise_for_status()
return response.content
pdf_bytes = compile_with_custom_class("./my-paper")
with open("paper.pdf", "wb") as f:
f.write(pdf_bytes)This walks your entire project directory and sends every file to the API, preserving the relative path structure. It works for any depth of nesting. The same pattern applies when building reusable LaTeX API document templates — you structure shared class files once and reference them across all your projects.
Debugging Failed Multi-File Compilations
When a multi-file compilation fails, the API returns the full LaTeX log in the error response. Common failure patterns and their causes:
File 'sections/introduction.tex' not found— the file path in yourfilesarray does not match what\includeexpects. Check for trailing slashes, mismatched capitalization, or missing.texextension.Citation 'smith2023' undefined— you usedpdflatexinstead oflatexmk, or your.bibfile is missing from thefilesarray.\documentclass{acmart} not found— the.clsfile is missing or its path in thefilesarray does not match the\documentclassargument.Package biblatex Error: File 'references.bib' not found— the path passed to\addbibresourcedoes not match the path in yourfilesarray exactly.
For a complete reference of error codes and what each status means, see the LaTeX API error codes guide.
To inspect the log programmatically:
const response = await fetch(API_URL, { method: "POST", headers, body });
if (!response.ok) {
const error = await response.json();
// error.log contains the full LaTeX compiler output
console.error("Compilation log:\n", error.log);
throw new Error(error.error);
}Reading the log directly is faster than guessing. The LaTeX error messages are verbose but precise.
Plan Limits for Multi-File Projects
Multi-file compilation does not cost more per job — one API call is one compilation regardless of how many files are in the payload. What matters for plan selection is total payload size and the engine you need:
- The Free plan supports only
pdflatexand caps payload size at 1 MB. Adequate for simple documents, but not for bibliography workflows or custom classes. - The Developer plan at $12/month unlocks all four engines including
latexmk, which is required for bibliography compilation. - The Pro plan at $49/month raises the size limit to 10 MB, covering most academic projects including embedded figures.
- The Scale plan at $199/month supports up to 25 MB payloads, suitable for books, dissertations, and large reports.
Start Compiling Multi-File Documents Today
Multi-file LaTeX API compilation is available on all paid FormatEx plans. You send the files, FormatEx handles the TeX Live infrastructure, and you get a PDF back — no Docker containers, no TeX installation, no build scripts to maintain. If you are evaluating whether to self-host TeX Live vs. use a compilation API, the infrastructure savings become especially clear when you factor in multi-pass bibliography compilation across many projects.
Sign up at formatex.io to get your API key. The free tier lets you test single-file documents immediately; upgrade to Developer or higher when you are ready to compile full academic papers with bibliography passes and custom document classes.
Related Articles
- The Complete Guide to LaTeX Engines — Covers pdfLaTeX, XeLaTeX, LuaLaTeX, and latexmk in depth, including when multi-pass compilation is required
- Automating Academic Paper PDFs with the LaTeX API — End-to-end workflow for generating academic papers, theses, and scientific reports via API
- LaTeX API Document Templates That Scale — Reusable template patterns for multi-file projects including variable substitution and shared class files
- LaTeX API Error Codes: Complete Guide — Full reference for 422 compile failures and how to interpret LaTeX log output from the API
- Self-Hosting LaTeX vs. Using a Compilation API — Cost and maintenance analysis that makes the case for offloading TeX Live infrastructure
\end{article}
\related{posts}




