Next.js SEO Checklist: What Developers Miss
Next.js is one of the best frameworks for SEO. Server-side rendering, static generation, built-in metadata API, automatic code splitting — it gives you everything you need. And yet, most Next.js sites have SEO problems.
Not because the framework is lacking. Because developers focus on building features and assume SEO "just works" with SSR. It doesn't. Here's what you're probably missing.
SSR vs. SSG vs. ISR — Pick the Right One
Next.js gives you three rendering strategies. Each has SEO implications:
- Static Site Generation (SSG) — Pages are built at build time. Best for content that doesn't change often: blog posts, landing pages, documentation. Google gets a fully-rendered HTML page with zero latency. This is your best option for SEO when possible.
- Server-Side Rendering (SSR) — Pages are rendered on each request. Use this for personalized or frequently-changing content: dashboards, search results, user-specific pages. SEO is fine as long as your server responds quickly (under 200ms ideally).
- Incremental Static Regeneration (ISR) — The best of both worlds. Pages are statically generated but revalidated on a schedule. Great for product pages, blog indexes, and anything that changes occasionally but doesn't need real-time data.
The mistake: Using SSR for everything. If a page could be static, make it static. SSR adds server latency on every request, and if your server is slow or overloaded, Google will notice.
The Metadata API — Use It Properly
Next.js 13+ introduced the Metadata API with the App Router. It's powerful, but most developers only scratch the surface:
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title + " — YourSite",
description: post.excerpt,
alternates: {
canonical: `https://yoursite.com/blog/${params.slug}`,
},
openGraph: {
title: post.title,
description: post.excerpt,
type: "article",
publishedTime: post.date,
url: `https://yoursite.com/blog/${params.slug}`,
},
};
}What most developers miss:
- Canonical URLs — Every page needs one. Without it, Google might index URL variants (with query params, trailing slashes, etc.) as separate pages. Use
alternates.canonicalin the metadata object. - Open Graph tags — Not just for social sharing. Google uses OG tags as fallback data. Include
og:title,og:description,og:type, andog:urlon every page. - Dynamic metadata for dynamic routes — If you have
[slug]routes, usegenerateMetadatato pull title and description from your data. Don't hard-code a generic title that's the same for every page. - Robots meta per page — Some pages shouldn't be indexed (search results, filtered views, auth pages). Use the
robotsfield in metadata to set noindex on a per-page basis.
Sitemap Generation
Next.js supports sitemap.ts (or sitemap.xml) in the app directory. Most developers either skip it entirely or create a static one that goes stale.
The right approach:
// app/sitemap.ts
export default async function sitemap() {
const posts = await getAllPosts();
const postUrls = posts.map(post => ({
url: `https://yoursite.com/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: "monthly",
priority: 0.7,
}));
return [
{ url: "https://yoursite.com", priority: 1.0 },
...postUrls,
];
}Key points:
- Generate dynamically — Don't maintain a static list. Pull from your CMS, database, or file system so new pages are automatically included.
- Include lastModified — Google uses this to prioritize crawling. If you update a page, the sitemap should reflect the new date.
- Submit to Search Console — Generate it, then submit it. Don't assume Google will find it on its own.
- Don't include noindex pages — If a page has noindex, it shouldn't be in the sitemap. This sends conflicting signals.
Structured Data (JSON-LD)
Next.js doesn't add structured data by default. You need to add it yourself, and most developers either skip it or add incorrect schema.
The cleanest approach in Next.js:
// components/json-ld.tsx
export function JsonLd({ data }: { data: object }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}
// In your layout or page:
<JsonLd data={{
"@context": "https://schema.org",
"@type": "Article",
headline: post.title,
datePublished: post.date,
author: { "@type": "Person", name: "Author Name" },
}} />Common schema types you should implement:
- Organization — On your homepage. Include name, logo, URL, and social profiles.
- Article / BlogPosting — On blog posts. Include headline, datePublished, author, and description.
- BreadcrumbList — On any page with breadcrumb navigation. Helps Google understand your site hierarchy.
- FAQPage — On FAQ sections. Can trigger rich snippets in search results (like we do on our FAQ page).
- Product — On product pages. Include price, availability, reviews, and SKU.
Use our Schema Generator to create JSON-LD for any schema type, then drop it into your Next.js component.
Common Next.js SEO Mistakes
Here's what we see when scanning Next.js sites with AuditMySite:
- Client-side only content — If important content is rendered inside a
useEffector behind a client-side API call, Google might not see it. Check by viewing your page source (Ctrl+U) — if the content isn't in the HTML, it's not reliably indexed. - Missing heading hierarchy — Developers use heading tags for styling instead of structure. Every page should have exactly one
h1, followed byh2s andh3s in logical order. Use the Heading Analyzer to check. - No robots.txt — Next.js doesn't generate one by default (in the Pages Router). In the App Router, create
app/robots.ts. Without it, you have no control over what gets crawled. - Trailing slash inconsistency — Next.js defaults to no trailing slash, but some configurations add one. Pick one and stick with it. Configure
trailingSlashinnext.config.jsand make sure canonical URLs match. - Missing alt text on next/image — The
Imagecomponent requires alt text, but developers often pass empty strings to satisfy the linter. Write real, descriptive alt text. - No error pages with proper status codes — Custom 404 and 500 pages should return the correct HTTP status codes. Next.js handles this with
not-found.tsxanderror.tsxin the App Router. Make sure they exist. - Forgetting about i18n — If your site serves multiple languages, use Next.js's built-in internationalization routing and add
hreflangtags. Missing hreflang means Google might show the wrong language version in search results.
Performance Matters More in Next.js Than You Think
Next.js apps can be fast, but they can also be slow. Common causes:
- Large JavaScript bundles — Use
next/dynamicfor heavy components that aren't needed on initial render. Check your bundle size with@next/bundle-analyzer. - Unoptimized images — Always use
next/image. It handles responsive sizes, lazy loading, and format conversion automatically. Don't use plain<img>tags. - Third-party scripts — Analytics, chat widgets, and tracking scripts can block rendering. Use
next/scriptwithstrategy="lazyOnload"for non-critical scripts. - Font loading — Use
next/fontto self-host fonts. This eliminates the extra round-trip to Google Fonts and prevents layout shift from font swapping.
The Next.js SEO Audit Workflow
- Scan your live site — Use AuditMySite to get a baseline. Check Technical SEO, On-Page, and Content categories.
- View page source — Right-click → View Source on your key pages. Verify that titles, descriptions, h1 tags, and content are in the server-rendered HTML.
- Check your sitemap — Visit
/sitemap.xml. Make sure all important pages are listed and none return 404s. - Validate structured data — Run your URLs through Google's Rich Results Test. Fix any errors or warnings.
- Test with Google Search Console — Use the URL Inspection tool to see exactly how Google renders your pages. Compare the rendered HTML to what you expect.
- Compare with competitors — Use the Compare tool to benchmark against sites ranking for your target keywords.
Next.js Gives You the Tools — Use Them
Next.js is arguably the most SEO-friendly React framework available. The Metadata API, automatic static optimization, built-in image optimization, and server components give you everything you need for excellent SEO.
But "everything you need" isn't the same as "everything done for you." You still need to implement canonical URLs, write proper metadata, add structured data, generate a sitemap, and avoid the client-side rendering trap.
Run your Next.js site through AuditMySite and see what you're missing. It checks all the things in this guide — and about 40 more — in 30 seconds.
Want to see how your site stacks up?
Run a free audit on AuditMySite — takes 30 seconds, no signup needed.
Scan Your Site Free →Get SEO tips in your inbox
Practical advice to improve your rankings. One email per week, no fluff.
No spam. Unsubscribe anytime.