Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LibreOffice headless conversion cheatsheet

verify

Convert documents from the command line with LibreOffice: no GUI, no clicks, scriptable. Every command in this cheatsheet was run and verified on LibreOffice 24.2 / Ubuntu 24.04 before being written down, including the timings and the failure modes. If a command is here, it works as shown.

Maintained by Converterer, a file-conversion API. If you'd rather not run LibreOffice yourself, that's what we're for, but this cheatsheet works entirely without us.

Install (headless server)

# Debian/Ubuntu: writer + calc + impress cover documents, spreadsheets, presentations.
# --no-install-recommends skips the GUI extras; this stays a few hundred MB.
sudo apt-get install -y --no-install-recommends \
  libreoffice-writer libreoffice-calc libreoffice-impress

The one command

soffice --headless --convert-to pdf report.docx
# -> report.pdf in the current directory, ~2-3s on a small VPS

Add --outdir to control where output lands:

soffice --headless --convert-to pdf report.docx --outdir /var/exports/

Notes that save you a search later:

  • Output is named after the input file; you cannot pick the output filename directly (rename afterwards).
  • Existing output files are overwritten without prompting (Overwriting: appears in the log).
  • Warning: failed to launch javaldx is harmless for conversions; ignore it.

Conversions that just work

soffice --headless --convert-to pdf  report.docx     # Word -> PDF
soffice --headless --convert-to pdf  data.xlsx       # Excel -> PDF
soffice --headless --convert-to pdf  deck.pptx       # PowerPoint -> PDF
soffice --headless --convert-to odt  report.docx     # Word -> OpenDocument
soffice --headless --convert-to xlsx data.csv        # CSV -> Excel
soffice --headless --convert-to docx report.odt      # OpenDocument -> Word

When you must name the filter

Some targets need an explicit filter name, and the error when you skip it is unhelpfully terse:

soffice --headless --convert-to docx report.html
# Error: no export filter

That happens when the document type LibreOffice picked on import (here: a Writer/Web document) has no default mapping to your target. Name the filter and it works:

soffice --headless --convert-to "docx:MS Word 2007 XML" report.html

Filter names verified in this cheatsheet:

Target Filter string
PDF (from Writer docs) pdf:writer_pdf_Export
PDF (from Calc) pdf:calc_pdf_Export
PDF (from Impress) pdf:impress_pdf_Export
DOCX docx:MS Word 2007 XML
ODT odt:writer8
XLSX xlsx:Calc Office Open XML
PPTX pptx:Impress MS PowerPoint 2007 XML
HTML (from Writer docs) html:HTML (StarWriter)
CSV csv:Text - txt - csv (StarCalc)

PDF export options

Filter options ride after a second colon as JSON (LibreOffice 7.4+):

# Export only page 1
soffice --headless --convert-to \
  'pdf:writer_pdf_Export:{"PageRange":{"type":"string","value":"1"}}' report.docx

Other useful keys in writer_pdf_Export follow the same pattern (SelectPdfVersion for PDF/A, Quality for image compression, EncryptFile + DocumentOpenPassword for protection); the full list is in the PDF export CLI parameter reference.

CSV: delimiters and encodings

CSV options use a comma-separated token string, not JSON. The two you need:

Exporting (which delimiter/encoding to write):

# 44 = comma (ASCII), 34 = double-quote, 76 = UTF-8, 1 = from first row
soffice --headless --convert-to "csv:Text - txt - csv (StarCalc):44,34,76,1" data.xlsx

Importing (how to read a non-standard CSV, e.g. semicolon-separated):

# 59 = semicolon: parses data-semicolon.csv into real columns, then writes xlsx
soffice --headless --infilter="CSV:59,34,76,1" --convert-to xlsx data-semicolon.csv

Without --infilter, a semicolon CSV imports as one column per row. The tokens are ASCII codes for the field delimiter and text delimiter, then a character-set code (76 = UTF-8), then the first data row. Full token reference: CSV filter parameters.

Batch: one invocation beats a loop

--convert-to accepts multiple files, and startup dominates small conversions. Measured on the same machine, same four DOCX files:

# 5.96s total
soffice --headless --convert-to pdf a.docx b.docx c.docx d.docx --outdir out/

# 13.52s total
for f in a b c d; do soffice --headless --convert-to pdf $f.docx --outdir out/; done

Shell globs work too: soffice --headless --convert-to pdf *.docx.

The concurrency trap (read this before CI)

Two soffice instances cannot share one user profile. The second doesn't error loudly; it exits 1 and produces nothing:

soffice --headless --convert-to pdf a.docx &   # works
soffice --headless --convert-to pdf b.docx &   # exit code 1, no output file

This is the classic "conversions randomly missing in CI" bug. The fix is one flag: give each concurrent instance its own profile directory.

soffice --headless -env:UserInstallation=file:///tmp/lo_profile_$$ \
  --convert-to pdf report.docx

Both instances succeed when run this way (verified). In a worker pool, derive the profile path from the worker ID. First run with a fresh profile pays a small bootstrap cost; reuse per-worker profiles rather than deleting them each time.

Errors decoded

Message What it actually means
Error: no export filter The import document type can't auto-map to your target. Name the filter explicitly (see table above).
second instance produces no output, exit 1 Profile lock: another soffice is using the same user profile. Use -env:UserInstallation.
Error: source file could not be loaded Path/permission problem, or the file genuinely isn't the format its extension claims. Check the file is readable from the process's working context.
Warning: failed to launch javaldx Harmless for conversions. Java is only needed for a few features (some Base/macros paths).

Production notes

  • Conversions are sequential within one instance; parallelism = multiple instances with separate profiles.
  • Fonts must be installed at the OS level (fontconfig); a DOCX using fonts the server lacks silently falls back, changing layout and page breaks. Install the fonts your documents use.
  • Fidelity is very good for typical office documents, but complex Word layouts can shift. If exact Word rendering matters, compare outputs before committing a pipeline.
  • Wrap invocations in a timeout (timeout 120 soffice ...): a corrupt input can hang rather than fail.

Verified by CI, not by vibes

Everything above is re-run automatically: scripts/verify.sh executes the documented commands against the fixtures/ and asserts outputs exist with the right MIME types (including the one-page PageRange export and the separate-profile concurrency case). GitHub Actions runs it on every push and weekly on Ubuntu 22.04 and 24.04, so if a LibreOffice update changes behaviour, this cheatsheet finds out before you do. Run it yourself: scripts/verify.sh.

Official references


Related, from the same hand-tested series: HTML to PDF: the complete guide (9 renderers compared with downloadable output) · wkhtmltopdf migration guide

Corrections welcome: if a command doesn't behave as documented on a current LibreOffice, open an issue with your version and OS.

Releases

Packages

Contributors

Languages