Customize Application Fonts | Next.js Supabase SaaS Kit
Configure custom fonts using Google Fonts, local fonts, or system fonts in your Makerkit application with Next.js font optimization.
Customize your application's typography by editing apps/web/lib/fonts.ts. This file defines the font families used throughout your app, with Next.js automatically handling font optimization, subsetting, and self-hosting for privacy and performance.
By default, Makerkit uses Apple's system font on Apple devices (San Francisco) and falls back to Inter on other platforms.
Quick Font Change
Replace the default Inter font with any Google Font:
import { Poppins as SansFont } from 'next/font/google';import { cn } from '@kit/ui/utils';const sans = SansFont({ subsets: ['latin'], variable: '--font-sans-fallback', fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'], preload: true, weight: ['300', '400', '500', '600', '700'],});const heading = sans;export { sans, heading };export function getFontsClassName(theme?: string) { const dark = theme === 'dark'; const light = !dark; const font = [sans.variable, heading.variable].reduce<string[]>( (acc, curr) => { if (acc.includes(curr)) return acc; return [...acc, curr]; }, [], ); return cn(...font, { dark, light });}Using Different Fonts for Headings and Body
Create visual hierarchy by using different fonts for headings and body text:
import { Inter as SansFont, Playfair_Display as HeadingFont } from 'next/font/google';import { cn } from '@kit/ui/utils';const sans = SansFont({ subsets: ['latin'], variable: '--font-sans-fallback', fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'], preload: true, weight: ['300', '400', '500', '600', '700'],});const heading = HeadingFont({ subsets: ['latin'], variable: '--font-heading', fallback: ['Georgia', 'Times New Roman', 'serif'], preload: true, weight: ['400', '500', '600', '700'],});export { sans, heading };export function getFontsClassName(theme?: string) { const dark = theme === 'dark'; const light = !dark; const font = [sans.variable, heading.variable].reduce<string[]>( (acc, curr) => { if (acc.includes(curr)) return acc; return [...acc, curr]; }, [], ); return cn(...font, { dark, light });}Then update apps/web/styles/shadcn-ui.css to use the heading font:
@layer base { :root { --font-sans: -apple-system, BlinkMacSystemFont, var(--font-sans-fallback); --font-heading: var(--font-heading), Georgia, serif; }}Using Local Fonts
For fonts not available on Google Fonts, or for complete control over font files:
import localFont from 'next/font/local';import { cn } from '@kit/ui/utils';const sans = localFont({ src: [ { path: '../fonts/CustomFont-Regular.woff2', weight: '400', style: 'normal', }, { path: '../fonts/CustomFont-Medium.woff2', weight: '500', style: 'normal', }, { path: '../fonts/CustomFont-Bold.woff2', weight: '700', style: 'normal', }, ], variable: '--font-sans-fallback', fallback: ['system-ui', 'Helvetica Neue', 'Helvetica', 'Arial'], preload: true,});const heading = sans;export { sans, heading };Place font files in apps/web/fonts/ directory. Supported formats: .woff2 (recommended), .woff, .ttf, .otf.
Removing Apple System Font Default
By default, Makerkit prioritizes Apple's system font on macOS and iOS for a native feel. To use your chosen font consistently across all platforms:
Edit apps/web/styles/shadcn-ui.css:
@layer base { :root { /* Remove -apple-system and BlinkMacSystemFont to use your font everywhere */ --font-sans: var(--font-sans-fallback); --font-heading: var(--font-sans); }}This ensures your Google Font or local font displays on Apple devices instead of San Francisco.
Popular Font Combinations
Modern SaaS (Clean and Professional)
import { Inter as SansFont } from 'next/font/google';// Headings and body: InterEditorial (Content-Heavy Apps)
import { Source_Sans_3 as SansFont, Source_Serif_4 as HeadingFont } from 'next/font/google';// Body: Source Sans 3// Headings: Source Serif 4Startup (Friendly and Approachable)
import { DM_Sans as SansFont } from 'next/font/google';// Headings and body: DM SansTechnical (Developer Tools)
import { IBM_Plex_Sans as SansFont, IBM_Plex_Mono as MonoFont } from 'next/font/google';// Body: IBM Plex Sans// Code: IBM Plex MonoPremium (Luxury/Finance)
import { Outfit as SansFont } from 'next/font/google';// Headings and body: OutfitFont Variable Reference
The font system uses CSS variables defined in two places:
| Variable | Defined In | Purpose |
|---|---|---|
--font-sans-fallback | fonts.ts | Next.js optimized font |
--font-heading | fonts.ts | Heading font (if different) |
--font-sans | shadcn-ui.css | Final font stack with system fallbacks |
Tailwind uses these through theme.css:
@theme { --font-sans: -apple-system, var(--font-sans); --font-heading: var(--font-heading);}Optimizing Font Loading
Preload Critical Fonts
const sans = SansFont({ // ... preload: true, // Preload for faster initial render display: 'swap', // Show fallback immediately, swap when loaded});Subset for Faster Loading
const sans = SansFont({ // ... subsets: ['latin'], // Only load Latin characters // Or load multiple subsets if needed: // subsets: ['latin', 'latin-ext', 'cyrillic'],});Specify Only Needed Weights
const sans = SansFont({ // ... weight: ['400', '500', '700'], // Only weights you actually use // Avoid: weight: ['100', '200', '300', '400', '500', '600', '700', '800', '900']});Common Mistakes
Loading too many font weights: Each weight adds to bundle size. Only include weights you actually use (typically 400, 500, 600, 700).
Forgetting to update CSS variables: After changing fonts in fonts.ts, you may need to update shadcn-ui.css if you want to remove the Apple system font priority or configure the heading font.
Using display: 'block': This causes invisible text until fonts load (FOIT). Use display: 'swap' for better perceived performance.
Not testing on Windows: Apple system fonts don't exist on Windows. Always test your fallback fonts on non-Apple devices.
Verification
After updating fonts:
- Check the Network tab in DevTools for font files loading
- Verify fonts render on both Mac and Windows
- Test with slow network throttling to see fallback behavior
- Run Lighthouse to check for font-related performance issues
# Quick check for font loadingpnpm dev# Open DevTools > Network > Filter: Font# Verify your custom font files are loadingFrequently Asked Questions
Why does my custom font not appear on Mac?
How do I add a monospace font for code blocks?
Can I use variable fonts?
How do I improve font loading performance?
Next Steps
- Back to Customization Overview
- Configure your theme colors to complement your typography
- Set up your layout style for navigation
- Update your application logo