Home Quizzes Leaderboard Competitions Learn Hire Us
About Contact
Log In Sign Up
Learn Next.js Images, Fonts & Static Assets

Images, Fonts & Static Assets

⏱ 12 min read read
next/image --- Automatic Optimisation:

Always use next/image instead of <img>. It automatically resizes,
converts to WebP/AVIF, lazy-loads, and prevents layout shift.

import Image from 'next/image';

// Local image (from public/ folder)

<Image src="/hero.png" alt="Hero" width={1200} height={630}
priority />

// Remote image (must configure in next.config.js)

<Image

src="https://example.com/photo.jpg"

alt="Photo"

width={400}

height={300}

className="rounded-lg"

/>

// Fill parent container

<div style={{ position: 'relative', width: '100%', height: 400
}}>

<Image src="/bg.jpg" alt="Background" fill style={{ objectFit:
'cover' }} />

</div>

Allowing Remote Images in next.config.js:

// next.config.js

module.exports = {

images: {

remotePatterns: [

{ protocol: 'https', hostname: 'example.com' },

{ protocol: 'https', hostname: '*.githubusercontent.com' },

],

},

};

next/font --- Zero Layout Shift Fonts:

// app/layout.tsx

import { Inter, Fira_Code } from 'next/font/google';

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

const firaCode = Fira_Code({ subsets: ['latin'], variable:
'--font-mono' });

export default function RootLayout({ children }: { children:
React.ReactNode }) {

return (

<html lang="en" className={`${inter.variable}
${firaCode.variable}`}>

<body>{children}</body>

</html>

);

}

next/font downloads and self-hosts Google Fonts at build time --- no
external request.

Static files in public/ are served at / --- public/logo.png →
/logo.png.

next/image requires width + height OR fill prop --- prevents CLS
(layout shift).

Use priority on above-the-fold images to avoid LCP penalty.
Code Example
// components/CourseCard.tsx

import Image from 'next/image';

import Link from 'next/link';

interface CourseCardProps {

title: string;

description: string;

image: string;

slug: string;

duration: string;

lessons: number;

}

export default function CourseCard({

title, description, image, slug, duration, lessons

}: CourseCardProps) {

return (

<Link href={`/courses/${slug}`} className="group block">

<div className="rounded-xl overflow-hidden border border-gray-200
hover:shadow-lg transition">

{/* Optimised image --- auto WebP, lazy-load, no CLS */}

<div className="relative w-full h-48">

<Image

src={image}

alt={title}

fill

sizes="(max-width: 768px) 100vw, 33vw"

style={{ objectFit: 'cover' }}

className="group-hover:scale-105 transition"

/>

</div>

<div className="p-4">

<h3 className="font-bold text-lg mb-1">{title}</h3>

<p className="text-gray-500 text-sm mb-3
line-clamp-2">{description}</p>

<div className="flex gap-4 text-xs text-gray-400">

<span>⏱ {duration}</span>

<span>📖 {lessons} lessons</span>

</div>

</div>

</div>

</Link>

);

}

// next.config.js --- allow remote images

/** @type {import('next').NextConfig} */

const nextConfig = {

images: {

remotePatterns: [

{ protocol: 'https', hostname: 'images.unsplash.com' },

{ protocol: 'https', hostname: 'avatars.githubusercontent.com' },

],

},

};

module.exports = nextConfig;
← Metadata, SEO & the Head Navigation & Middleware →

Log in to track your progress and earn badges as you complete lessons.

Log In to Track Progress