fontnome is a Python CLI tool for modifying font family names in OpenType and TrueType fonts. It manipulates specific nameID fields in the font's name table while preserving all other font data intact.
Install from PyPI:
pip install fontnomeOr using uv:
uv pip install fontnomeFor development:
git clone https://github.com/twardoch/fontnome
cd fontnome
uv pip install -e ".[dev]"When working with fonts, you often need to:
- Rename font families for testing or deployment
- Add version suffixes or timestamps to track iterations
- Create customized font builds with modified names
- Manage font naming across different platforms
fontnome makes these operations safe, predictable, and scriptable. It handles the complexity of OpenType name tables, ensuring that all relevant nameID fields are updated consistently.
# View current font family name
fontnome view MyFont.ttf
# Rename font family
fontnome new MyFont.ttf --new_family="Custom Font"
# Add timestamp (updates on each run)
fontnome timestamp MyFont.ttf
# Add suffix
fontnome suffix MyFont.ttf --suffix=" Beta"
# Find and replace in name
fontnome replace MyFont.ttf --find="Regular" --replace="Modified"fontnome operates on two distinct naming concepts:
-
family_name: Human-readable display name (e.g., "My Font Family")
- Read from: nameID 16 (Typographic Family) → 21 (WWS Family) → 1 (Font Family)
- Written to: nameIDs 1, 4, 16, 18, 21
-
family_slug: ASCII-safe PostScript identifier (e.g., "MyFontFamily")
- Read from: nameID 25 (Variations PostScript Name Prefix) → 6 (PostScript name, before first hyphen)
- Written to: nameIDs 6, 20, 25 (with spaces removed)
Slug generation converts any string to a PostScript-compatible identifier:
- Keeps only printable ASCII characters (codes 33-126)
- Removes these 10 forbidden characters:
[](){}<>/% - Removes all spaces
Example: "My Font [Beta]" → "MyFontBeta"
Timestamps are generated as lowercase base-36 Unix timestamps for compact, sortable identifiers.
Example: "t51r1v" (represents a specific Unix timestamp)
All operations use a safe writing pattern:
- Write to temporary file
- Optionally create backup of original
- Atomically move temporary file to final location
This prevents data loss and ensures you never end up with corrupted fonts.
All commands support short aliases (single letter) for faster typing.
fontnome view <input_path> [--long]
fontnome v <input_path> [--long]Parameters:
input_path: Input font file (.ttf, .otf)--long: Show path prefix in output (optional)
Examples:
$ fontnome view MyFont.ttf
My Font Family
$ fontnome v MyFont.ttf --long
MyFont.ttf:My Font Familyfontnome new <input_path> --new_family=<name> [--output_path=<mode>]
fontnome n <input_path> --new_family=<name> [--output_path=<mode>]Parameters:
input_path: Input font filenew_family: New family name to setoutput_path: Output mode (see Output Modes section)
Operation:
- Sets
new_family_nameto the provided value - Generates
new_family_slugusing SLUG_RULE - Updates all relevant nameID fields
Examples:
# Replace input file
$ fontnome new MyFont.ttf --new_family="Custom Font"
# Save to new file
$ fontnome n MyFont.ttf --new_family="Test" --output_path="output.ttf"
# Create backup before replacing
$ fontnome n MyFont.ttf --new_family="Production" --output_path="1"fontnome replace <input_path> --find=<text> --replace=<text> [--output_path=<mode>]
fontnome r <input_path> --find=<text> --replace=<text> [--output_path=<mode>]Parameters:
input_path: Input font filefind: Text to findreplace: Text to replace withoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Replaces
findwithreplaceinfamily_name - Converts both to slugs and replaces in
family_slug - Updates all relevant nameID fields
Examples:
$ fontnome replace MyFont.ttf --find="Draft" --replace="Final"
$ fontnome r MyFont.ttf --find="v1" --replace="v2"fontnome suffix <input_path> --suffix=<text> [--output_path=<mode>]
fontnome s <input_path> --suffix=<text> [--output_path=<mode>]Parameters:
input_path: Input font filesuffix: Suffix to appendoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Appends
suffixtofamily_name - Appends slug-converted suffix to
family_slug
Examples:
$ fontnome suffix MyFont.ttf --suffix=" Beta"
$ fontnome s MyFont.ttf --suffix=" v2.0"fontnome prefix <input_path> --prefix=<text> [--output_path=<mode>]
fontnome p <input_path> --prefix=<text> [--output_path=<mode>]Parameters:
input_path: Input font fileprefix: Prefix to prependoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Prepends
prefixtofamily_name - Prepends slug-converted prefix to
family_slug
Examples:
$ fontnome prefix MyFont.ttf --prefix="Draft "
$ fontnome p MyFont.ttf --prefix="Test "fontnome timestamp <input_path> [--separator=<text>] [--replace_timestamp] [--output_path=<mode>]
fontnome t <input_path> [--separator=<text>] [--replace_timestamp] [--output_path=<mode>]Parameters:
input_path: Input font fileseparator: Separator before timestamp (default:" tX")replace_timestamp: Remove old timestamp before adding new (default:True)output_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - If
replace_timestamp=Trueand using default separator:- Removes
tXand everything after fromfamily_name - Removes
tXand everything after fromfamily_slug
- Removes
- Generates new timestamp using TIME_RULE
- Appends
separator + timestamptofamily_name - Appends slug-converted suffix to
family_slug
Examples:
# Default: replaces old timestamp on each run
$ fontnome timestamp MyFont.ttf
# First run: "My Font" → "My Font tXt51r1v"
# Second run: "My Font tXt51r1v" → "My Font tXt51r2a"
# Keep accumulating timestamps
$ fontnome t MyFont.ttf --replace_timestamp=False
# Use custom separator
$ fontnome t MyFont.ttf --separator="-"All commands (except view) support flexible output handling via --output_path:
Replace input file safely:
fontnome new MyFont.ttf --new_family="Test" # --output_path="0" impliedCreate backup with timestamp, then replace input:
fontnome new MyFont.ttf --new_family="Test" --output_path="1"
# Creates: MyFont--t51r1v.ttf (backup)
# Updates: MyFont.ttf (modified)Save to timestamped output file, keep original:
fontnome new MyFont.ttf --new_family="Test" --output_path="2"
# Keeps: MyFont.ttf (original)
# Creates: MyFont--t51r1v.ttf (modified)Save to specific file:
fontnome new MyFont.ttf --new_family="Test" --output_path="Output.ttf"
# Keeps: MyFont.ttf (original)
# Creates: Output.ttf (modified)Enable debug logging for troubleshooting:
fontnome --verbose view MyFont.ttf
fontnome --verbose new MyFont.ttf --new_family="Test"When reading name records, fontnome tries:
- Windows English:
(platformID=3, platEncID=1, langID=0x409) - Mac Roman fallback:
(platformID=1, platEncID=0, langID=0)
family_name operations update:
- nameID 1: Font Family name (legacy)
- nameID 4: Full font name
- nameID 16: Typographic Family name
- nameID 18: Typographic Subfamily name
- nameID 21: WWS Family Name
family_slug operations update (no spaces):
- nameID 6: PostScript name
- nameID 20: PostScript CID findfont name
- nameID 25: Variations PostScript Name Prefix
The implementation is based on fonttools patterns. Reference code studied:
vendors/fonttools/Snippets/rename-fonts.pyvendors/fonttools/Lib/fontTools/varLib/instancer/names.py
Note: The vendors/ directory contains reference code only. fontnome uses the fonttools package from PyPI.
- Python 3.12+
- fonttools >= 4.50.0
- fire >= 0.6.0
- loguru >= 0.7.0
# Clone repository
git clone https://github.com/twardoch/fontnome
cd fontnome
# Create virtual environment
uv venv --python 3.12
source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
# Install in development mode
uv pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run linting
ruff check src/
ruff format src/
# Run comprehensive test suite
./test.shfontnome includes comprehensive tests:
# Unit tests
pytest tests/test_utils.py -v # Slug and timestamp functions
pytest tests/test_core.py -v # Font name operations
# All tests with coverage
pytest tests/ --cov=fontnome --cov-report=html
# Functional tests (via test.sh)
./test.shTest coverage: 93-95% on core modules (utils.py, core.py).
Apache License 2.0
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
- PyPI: https://pypi.org/project/fontnome/
- GitHub: https://github.com/twardoch/fontnome
- Issues: https://github.com/twardoch/fontnome/issues
Created by Adam Twardoch
Based on fonttools by Just van Rossum and contributors.