Next.js · Lesson 5 of 5
SEO, Images and Deployment
Metadata, next/image, environment variables and deploying.
- Intermediate
- 14 min read
- 3 objectives
Before this lessonLesson 4: Route Handlers and Server Actions
What you will learn
- Set metadata
- Optimize images
- Deploy to Vercel or Docker
A good site is discoverable, fast and live on the internet. Next.js includes tools for all three.
Metadata for SEO
Export a metadata object (or an async generateMetadata for dynamic pages). Next.js renders the right <title> and meta tags into the HTML that search engines read.
// static
export const metadata = {
title: "Pricing | Acme",
description: "Simple pricing for teams of every size.",
openGraph: { title: "Pricing | Acme", images: ["/og.png"] },
};
// dynamic
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
return { title: post.title, description: post.excerpt };
}Also add app/sitemap.ts and app/robots.ts to generate sitemap.xml and robots.txt.
Images
next/image resizes and compresses images, serves modern formats, lazy-loads them and reserves space to avoid layout shift. Always give it dimensions (or fill).
import Image from "next/image";
<Image src="/hero.jpg" alt="Team at work" width={1200} height={600} priority />Use priority for the main above-the-fold image only. For remote images, allow the host in next.config.ts under images.remotePatterns.
Fonts
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
// <body className={inter.className}>Fonts are downloaded at build time and self-hosted, avoiding extra requests and layout jumps.
Environment variables
# .env.local (never commit)
DATABASE_URL=postgres://...
NEXT_PUBLIC_SITE_URL=https://example.comVariables are server-only by default. Only names starting with NEXT_PUBLIC_ are exposed to the browser, so never put secrets in them.
Build and deploy
npm run build # compile and show which routes are static or dynamic
npm start # run the production server- Vercel: push to GitHub, import the repo, done. The easiest option.
- Docker: set
output: "standalone"in the config and copy the standalone build into a small image. - Static export:
output: "export"produces plain files for any static host, if you use no server features.
// Write your solution here
