The Problem
Typography should be one of the simplest parts of a project.
In reality, it often ends up scattered across multiple layers:
- Bootstrap:
$font-family-basevariables - Tailwind: JavaScript configuration
- TypeScript: type definitions
- Design systems: W3C Design Tokens
The same font information gets copied and maintained in several places. Every update means touching multiple files, hoping everything stays in sync.
It's repetitive, error-prone, and easy to get wrong.
So I built Font Manager.
Define your fonts once and export them in whatever format your project needs — CSS, Bootstrap variables, Tailwind configuration, TypeScript definitions, design tokens, and more.
The Solution
A simple Twig function:
{{ font_manager('Ubuntu', '400 700') }}
Configuration:
symfinity_font_manager:
export:
formats:
- scss_bootstrap
- tailwind_config
- typescript_definitions
One lock command:
php bin/console fonts:lock
Every format, automatically generated. Perfectly synced.
Bootstrap Example
Before:
// Manually copy font name
$font-family-base: 'Ubuntu', sans-serif; // ❌ Duplication
@import 'bootstrap/scss/bootstrap';
After:
symfinity_font_manager:
export:
formats: [scss_bootstrap]
php bin/console fonts:lock
// app.scss
@import './assets/styles/fonts-bootstrap'; // ← Auto-generated
@import 'bootstrap/scss/bootstrap';
Bootstrap uses your fonts automatically. No manual mapping. No duplication.
Tailwind Example
symfinity_font_manager:
export:
formats: [tailwind_config]
// tailwind.config.js
const fonts = require('./assets/fonts-tailwind.config.js'); // ← Auto-generated
module.exports = {
theme: { extend: { fontFamily: fonts.fontFamily } }
};
<p class="font-sans">Your custom font, via Tailwind.</p>
TypeScript Example
symfinity_font_manager:
export:
formats: [typescript_definitions]
import { fonts, type FontFamily } from './assets/fonts';
applyFont(element, 'sans'); // ✓ Valid
applyFont(element, 'invalid'); // ✗ TypeScript error!
Typos caught at compile time.
The 12 Formats
CSS, SCSS, JavaScript, Design Tokens — pick what you need:
php bin/console fonts:formats
CSS: Variables, Modules, @layer
SCSS: Variables, Bootstrap, Mixins
JavaScript: ESM, Tailwind, TypeScript
Design System: JSON, W3C Tokens, Figma, Style Dictionary
Build Tools
AssetMapper, Webpack, or Vite? Auto-detected.
Output paths adjust automatically. No config needed.
Design Systems
Export to Figma Tokens, Style Dictionary, or W3C Design Tokens:
formats:
- design_tokens
- figma_tokens
npx style-dictionary build # CSS, iOS, Android from one source
Design once. Ship everywhere.
Privacy Options
Not just Google — choose your provider:
symfinity_font_manager:
default_provider: 'bunny' # GDPR-compliant, zero tracking
Google, Bunny, Fontsource, or Local. Same API. Your choice.
How It Works
Architecture: Strategy pattern. Each format is a separate exporter.
Dependency resolution: Automatic. css_modules needs css_variables? Handled.
Build detection: Scans for webpack.config.js, vite.config.js, asset_mapper.yaml.
Output paths: Adjusted per build tool. AssetMapper → assets/styles/. Webpack → assets/.
Commands:
php bin/console fonts:formats # List all formats
php bin/console fonts:format:info scss # Usage instructions
php bin/console fonts:export # Export manually
Migrating from google-fonts
One command:
php bin/console fonts:migrate-from-google-fonts
Config, templates, manifest — all updated automatically.
Prerequisite
Go to github.com/symfinity/recipes and follow the instructions to add the required recipe repository.
Installation
composer require symfinity/font-manager
That’s it. Symfony Flex does the rest.
Quick Start
{{ font_manager('Ubuntu', '400 700') }}
Dev: CDN
Prod: Self-hosted (after fonts:lock)
Add exports:
symfinity_font_manager:
export:
formats: [scss_bootstrap, tailwind_config]
Lock:
php bin/console fonts:lock
Use:
@import './fonts-bootstrap';
@import 'bootstrap/scss/bootstrap';
Done.
Conclusion
Typography shouldn’t waste your time or violate privacy law.
With font-manager, you can design freely in development, ship safely in production, and forget about fonts altogether.
One Twig function. Multiple providers. Twelve export formats. Zero manual mapping.
That’s Font Manager.
Try it now: symfinity/font-manager
If you find it useful, star the repository and share it with your Symfony community.
What's next
Don't miss the introduction series to Symfinity:
- Part 1: Why building Symfony-native packages instead of doing infrastructure again and again
- Part 2: Why Symfony projects feel more fragmented than ever
- Part 3: The rule behind every Symfinity package
Another package-level deep dive:
Articles on further Symfinity package tiers are planned, this is just the beginning.
Explore packages and source at github.com/symfinity.
This article was previously published on medium.com.
Top comments (0)