Skip to content

Configure fonts

Mats Alm edited this page Jul 1, 2026 · 2 revisions

When EPPlus renders text to an image-based format it needs to measure and shape the text using real font data. This applies to the HTML/SVG and PDF exports. EPPlus ships with sensible defaults and a built-in fallback chain, so in most cases you don't need to configure anything — but when you do, Workbook.ConfigureFonts lets you control where fonts are loaded from and how missing fonts and glyphs are handled.

Font configuration is applied per workbook and must be set before you export. It does not affect any other workbook or any global state.

Default behaviour

If you never call ConfigureFonts, EPPlus resolves fonts like this:

  • The operating system's standard font directories are searched.
  • If a requested font can't be found, EPPlus walks its built-in fallback chains and, as a last resort, uses the embedded Archivo Narrow font, so rendering never fails just because a font is missing.
  • Emoji and mathematical symbols are always served by the bundled Noto Emoji and Noto Math fonts.

Because of this, a workbook containing Latin text will always render, even on a server with no fonts installed. Note, however, that EPPlus does not bundle fonts for every writing system — large scripts such as CJK (Chinese, Japanese, Korean) are not included. To render text in those scripts you need an appropriate font available, either installed on the machine or supplied through FontDirectories and, where needed, a per-script fallback. If no suitable font is available, the characters will render as missing-glyph boxes rather than readable text.

Configuring fonts

Call ConfigureFonts on the workbook and mutate the configuration inside the callback. The example below adds a custom font directory and turns off the system font search, so that only your directory is used:

using var package = new ExcelPackage();
package.Workbook.ConfigureFonts(cfg =>
{
    cfg.FontDirectories.Add(@"C:\MyFonts");
    cfg.SearchSystemDirectories = false;
});

// ...add drawings/charts, then export

The changes you make inside the callback are applied as a single transaction — when the callback returns, the font resolver is rebuilt and the workbook's font caches are cleared.

Here are the members you can use inside the callback:

Member Data type Description
FontDirectories IList<string> Additional directories to search for font files, beyond the system font directories.
SearchSystemDirectories bool Whether the operating system's standard font directories are searched. Defaults to true. Set to false to restrict resolution to FontDirectories.
FontFallbacks IDictionary<string, string[]> User-defined font-name fallback chains. Maps a font name to an ordered list of fonts to try when the primary is unavailable. See Fallback chains.
SetScriptFallback(...) method Replaces the per-script glyph fallback chain for a given Unicode script. See Per-script fallback.
FontResolver IFontResolver Replaces the font resolver entirely. For advanced scenarios — see Advanced: custom font resolution.

Fallback chains

A fallback chain tells EPPlus which fonts to try when a requested font isn't available. Add an entry to FontFallbacks, mapping the primary font name to an ordered list of alternatives:

package.Workbook.ConfigureFonts(cfg =>
{
    // If "Corporate Sans" is not available, try these in order.
    cfg.FontFallbacks["Corporate Sans"] = new[] { "Arial", "Open Sans" };
});

User-defined chains are tried before EPPlus's built-in fallback chains. If none of the fonts in the chain can be found, resolution continues with the built-in chains and, ultimately, the embedded Archivo Narrow font.

Per-script fallback

Font-level fallbacks kick in when an entire font is missing. But sometimes a font is available and is used for most of the text, yet lacks glyphs for a particular writing system — for example a Latin font that has no Japanese characters. Per-script fallback handles this at the glyph level: when the primary font lacks a glyph for a character that belongs to a given script, EPPlus walks the script's fallback chain and uses the first font that contains the glyph.

Configure a script's chain with SetScriptFallback:

package.Workbook.ConfigureFonts(cfg =>
{
    cfg.FontDirectories.Add(@"C:\MyFonts");

    // Use "Noto Sans JP" for Han (Chinese/Japanese/Korean ideographs)
    // when the primary font lacks those glyphs.
    cfg.SetScriptFallback(UnicodeScript.Han, "Noto Sans JP");
});

A few things to keep in mind:

  • Setting a chain fully replaces the built-in default for that script — there is no merge. You become responsible for providing a complete chain for that script.
  • Pass no font names (an empty chain) to disable fallback for a script entirely: cfg.SetScriptFallback(UnicodeScript.Han);
  • Emoji and Math are always served by the bundled Noto Emoji and Noto Math fonts, regardless of this configuration.

The UnicodeScript enum covers the scripts that are realistic in Office documents, including Latin, Cyrillic, Greek, Arabic, Hebrew, Thai, Devanagari, Han, Hiragana, Katakana and Hangul.

How fonts are resolved

When EPPlus needs a font for a piece of text, it resolves it in this order:

  1. The requested font, if it can be found in the configured directories (and system directories, unless disabled).
  2. A user-defined font fallback chain for that font name, if one is configured.
  3. EPPlus's built-in font fallback chains.
  4. For individual characters the resolved font can't cover, the per-script glyph fallback for that character's script.
  5. As a final guarantee, the embedded Archivo Narrow font.

Because step 5 always succeeds, rendering never throws simply because a font or glyph is missing.

Advanced: custom font resolution

The font pipeline is built around interfaces, so its parts can be replaced when the built-in behaviour isn't enough. Most notably, you can supply your own FontResolver to take full responsibility for producing font data — for example to load fonts from a database or an embedded resource instead of the file system.

package.Workbook.ConfigureFonts(cfg =>
{
    cfg.FontResolver = new MyCustomFontResolver();
});

Note that when you set a custom resolver, EPPlus's built-in fallback chains and the Archivo Narrow ultimate fallback are bypassed — your resolver becomes fully responsible for handling missing fonts.

Which exports use the font pipeline

Font configuration affects the exports that measure and shape text against real font data:

  • HTML/SVG export — charts and shapes rendered to SVG.
  • PDF export.

Other operations, such as saving the workbook as an .xlsx file, are not affected by this configuration.

See also

EPPlus wiki

Versions

Worksheet & Ranges

Styling

Import/Export data

Formulas and filters

Charts & Drawing objects

Tables & Pivot Tables

VBA & Protection

Clone this wiki locally