Next.js 16 Google Fonts: Global Inter & Exo 2 Setup

Use next/font/google to self-host Inter for body and Exo 2 for headings with Tailwind; zero layout shift and global…

·Matija Žiberna·
Next.js 16 Google Fonts: Global Inter & Exo 2 Setup

⚡ Next.js Implementation Guides

In-depth Next.js guides covering App Router, RSC, ISR, and deployment. Get code examples, optimization checklists, and prompts to accelerate development.

No spam. Unsubscribe anytime.

I was setting up typography for a manufacturing website when I realized I needed different fonts for headings versus body text. Rather than manually applying fonts to every component, I discovered Next.js 16's built-in next/font/google module handles everything elegantly—with automatic self-hosting and zero layout shift.

Here's the exact process I used to set up Inter for body text and Exo 2 for all headings, globally.

Step 1: Import and Configure Your Fonts

Open your root layout file and import the fonts you want from next/font/google. In this case, we're using Inter for body text and Exo 2 for headings.

// File: app/layout.tsx
import type { Metadata } from "next";
import { Geist, Geist_Mono, Inter, Exo_2 } from "next/font/google";
import { Toaster } from "sonner";
import Navbar from "@/app/components/navbar";
import Footer from "@/app/components/footer";
import { navbarExample, footerExample } from "@/app/data";
import "./globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

const inter = Inter({
  variable: "--font-inter",
  subsets: ["latin"],
});

const exo2 = Exo_2({
  variable: "--font-exo-2",
  subsets: ["latin"],
});

Each font is initialized with a CSS variable name (like --font-inter). This variable becomes available throughout your application. The subsets: ["latin"] option ensures only the Latin character set is loaded, optimizing performance.

Step 2: Apply Fonts to the Root Layout

Update your HTML body to include the font variables and the default body font class:

// File: app/layout.tsx (continued)
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html>
      <body
        className={`${geistSans.variable} ${geistMono.variable} ${inter.variable} ${exo2.variable} ${inter.className} antialiased`}
      >
        <Navbar data={navbarExample} />
        {children}
        <Footer data={footerExample} />
        <Toaster />
      </body>
    </html>
  );
}

Notice we're including all font variables (making them available via CSS) and applying inter.className to the body itself, which sets Inter as the default font for all text content.

Step 3: Update Your Tailwind Theme Configuration

Now configure Tailwind to use these fonts. Update your globals.css file to map the font variables into Tailwind's theme:

/* File: app/globals.css */
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --font-sans: var(--font-inter);
  --font-mono: var(--font-geist-mono);
  --font-heading: var(--font-exo-2);
  /* ... rest of your theme ... */
}

By setting --font-sans: var(--font-inter), Tailwind will use Inter for all body text by default. The new --font-heading: var(--font-exo-2) line creates a custom font family that we'll use for headings.

Step 4: Apply Headings Font Automatically

In the same globals.css file, add a base layer rule that applies the heading font to all heading elements:

/* File: app/globals.css */
@layer base {
  * {
    @apply border-border outline-ring/50;
  }
  body {
    @apply bg-background text-foreground;
  }
  h1, h2, h3, h4, h5, h6 {
    @apply font-heading;
  }
}

This CSS rule is the magic piece. Every h1 through h6 element in your entire application will automatically use the Exo 2 font. No component modifications needed.

How This All Works Together

When your application loads, Next.js automatically:

  1. Optimizes the Google Fonts (removes external network requests)
  2. Self-hosts them from your domain
  3. Prevents layout shift by properly sizing fonts during load
  4. Applies Inter as the default body font via the inter.className on your body element
  5. Makes --font-exo-2 available as a CSS variable

Your Tailwind configuration then maps these fonts into utility classes (font-sans for body, font-heading for headings), and the base layer rule ensures every heading automatically gets the Exo 2 treatment without manual intervention in any component.

Result

You now have a complete, global font system where:

  • All body text uses Inter
  • All headings automatically use Exo 2
  • Zero components need modification
  • Fonts are self-hosted and optimized
  • No external requests or layout shift

The beauty of this approach is that any component using standard semantic HTML heading tags (h1, h2, etc.) automatically gets the right font. No need to add classes or think about typography in individual components.


Let me know in the comments if you have questions, and subscribe for more practical development guides.

Thanks, Matija

0

Frequently Asked Questions

Comments

Leave a Comment

Your email will not be published

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.