Next.js gives you the tools for great SEO. But "tools available" and "SEO done right" are very different things. After shipping dozens of Next.js projects, I've built a checklist I run on every single one. Here it is — the complete list with code examples.
Why Next.js SEO Isn't Automatic
Out of the box, Next.js gives you server-side rendering, which is a head start. But Google's crawlers look for a lot more than rendered HTML. They want structured data, proper metadata, fast load times, mobile optimization, and internal linking.
None of that comes free with npx create-next-app.
The 15-Point Checklist
1. Metadata API: Title Templates
Every page needs a unique title. The Metadata API makes this clean:
// app/layout.tsx
export const metadata: Metadata = {
title: {
default: 'Youness Haji — Full-Stack Developer',
template: '%s | Youness Haji',
},
description: 'Full-stack developer specializing in AI-powered web and mobile apps.',
};
The template pattern means child pages only need to set title: 'About' and it becomes "About | Youness Haji" automatically.
2. Open Graph Images
Every page shared on LinkedIn or Twitter needs an OG image. Generate them dynamically:
// app/api/og/route.tsx
import { ImageResponse } from '@vercel/og';
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get('title') || 'Youness Haji';
return new ImageResponse(
<div style={{ background: '#04050F', color: 'white', width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<h1 style={{ fontSize: 60 }}>{title}</h1>
</div>,
{ width: 1200, height: 630 }
);
}
Then reference it in your metadata:
openGraph: {
images: [{ url: '/api/og?title=My Page Title', width: 1200, height: 630 }],
}
3. JSON-LD Structured Data
Google uses structured data to create rich results. For a developer portfolio, Person schema is essential:
const personJsonLd = {
'@context': 'https://schema.org',
'@type': 'Person',
name: 'Youness Haji',
jobTitle: 'Full-Stack Developer',
url: 'https://younesshaji.com',
sameAs: [
'https://github.com/YounessHajiDev',
'https://linkedin.com/in/younesshaji',
],
};
For blog posts, use Article schema. For projects, use SoftwareApplication.
4. Sitemap Generation
Next.js 14 makes this native:
// app/sitemap.ts
export default function sitemap(): MetadataRoute.Sitemap {
const posts = getAllPosts();
return [
{ url: 'https://younesshaji.com', lastModified: new Date(), priority: 1 },
{ url: 'https://younesshaji.com/blog', lastModified: new Date(), priority: 0.9 },
...posts.map((post) => ({
url: `https://younesshaji.com/blog/${post.slug}`,
lastModified: new Date(post.date),
priority: 0.8,
})),
];
}
5. Robots.txt
// app/robots.ts
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: '*', allow: '/' },
sitemap: 'https://younesshaji.com/sitemap.xml',
};
}
6. Canonical URLs
Every page must have a canonical URL to prevent duplicate content issues:
alternates: {
canonical: 'https://younesshaji.com/blog/my-post',
}
7. Core Web Vitals
Google measures three metrics: LCP (Largest Contentful Paint), FID (First Input Delay), and CLS (Cumulative Layout Shift).
Quick wins:
- Use
next/imagewith explicit dimensions to prevent CLS - Use
next/fontfor font loading (prevents FOUT) - Lazy load below-the-fold components with
dynamic()
8. Image Optimization
Always use the Next.js <Image> component:
<Image
src="/project-screenshot.png"
alt="Descriptive alt text for accessibility and SEO"
width={800}
height={450}
priority={isAboveFold}
/>
The alt attribute isn't optional. It's how Google understands your images.
9. Internal Linking Architecture
Every page should link to at least 2 other pages on your site. This distributes "link juice" and helps Google discover all your content.
My rule: every blog post links to at least one project and ends with a link to contact.
10. Meta Descriptions
Every page needs a unique description under 155 characters. This is what shows up in Google search results.
description: 'Learn how to build AI-powered apps with Next.js and Groq. Step-by-step tutorial with code examples.',
11. Heading Hierarchy
Use exactly one <h1> per page. Structure content with <h2> and <h3> tags. Google uses headings to understand page structure.
12. URL Structure
Clean, descriptive URLs beat random slugs:
/blog/nextjs-seo-checklist-2025(descriptive)/blog/post-123(meaningless to Google)
13. Mobile Optimization
Google uses mobile-first indexing. Test every page on mobile viewport. Use responsive design, not separate mobile pages.
14. Page Speed
Use next build and check the output sizes. Pages over 200KB of JavaScript should be code-split. Use dynamic() imports for heavy components.
15. hreflang for Multilingual Sites
If your site supports multiple languages (like mine with EN/FR):
alternates: {
languages: {
'en': '/en',
'fr': '/fr',
},
}
The Quick Audit
Run this after every deploy:
- Google Search Console — submit sitemap, check for errors
- Lighthouse — aim for 90+ on all metrics
curl -I https://yousite.com— check response headers- Share a page on LinkedIn — verify OG image shows correctly
- Search
site:yousite.comon Google — verify pages are indexed
Conclusion
SEO isn't a one-time task. It's a system you build into your development workflow. This checklist is my system. Fork it, adapt it, and run it on every project.
The best time to add SEO was at the start of the project. The second best time is now.
Want to see this checklist in action? Check out how I implemented it on this very portfolio. Need SEO help on your Next.js project? Let's talk.