SEO
Learn how to optimize your NEXTDEVKIT website for search engines with metadata, sitemaps, and internationalization
🏗️ SEO System Architecture
NEXTDEVKIT's SEO system is structured as follows:
src/
├── lib/
│ └── metadata.ts # Centralized metadata management
├── app/
│ ├── [locale]/
│ │ └── layout.tsx # Root layout with metadata
│ ├── sitemap.ts # Automatic sitemap generation
│ └── robots.ts # Robots.txt configuration
├── config/
│ └── index.ts # Website configuration
├── messages/
│ ├── en.json # English translations
│ └── zh.json # Chinese translations
└── i18n/
└── routing.ts # Internationalization routing
⚙️ Metadata Configuration
Centralized Metadata Function
NEXTDEVKIT provides a centralized metadata function in src/lib/metadata.ts
:
import { appConfig } from "@/config";
import { getBaseUrl } from "@/lib/urls";
import type { Metadata } from "next";
export function metadata({
title,
description,
image,
canonicalUrl,
keywords,
}: {
title?: string | { template: string; default: string };
description?: string;
image?: string;
canonicalUrl?: string;
keywords?: string[];
} = {}): Metadata {
title = title || appConfig.metadata.title;
description = description || appConfig.metadata.description;
image = image || appConfig.metadata.images?.ogImage;
keywords = keywords || appConfig.metadata.keywords;
const ogImageUrl = image.startsWith("/")
? new URL(`${getBaseUrl()}${image}`)
: new URL(image);
return {
title,
description,
alternates: {
canonical: canonicalUrl || "./",
},
keywords,
openGraph: {
type: "website",
locale: "en_US",
url: canonicalUrl || getBaseUrl(),
title,
description,
siteName: appConfig.metadata.title,
images: [ogImageUrl.toString()],
},
twitter: {
card: "summary_large_image",
title,
description,
images: [ogImageUrl.toString()],
site: getBaseUrl(),
},
icons: [
{
rel: "icon",
url: "/favicon-96x96.png",
sizes: "96x96",
type: "image/png",
},
{ rel: "icon", url: "/favicon.svg", type: "image/svg+xml" },
{ rel: "shortcut icon", url: "/favicon.ico" },
{
rel: "apple-touch-icon",
url: "/apple-touch-icon.png",
sizes: "180x180",
},
],
metadataBase: new URL(getBaseUrl()),
};
}
Website Configuration
Configure your website's basic SEO settings in src/config/index.ts
:
export const appConfig = {
metadata: {
name: "NEXT DEV KIT",
title: "NEXTDEVKIT - Next.js Starter Kit",
description: "The Ultimate Next.js Starter Kit for Your Next Project",
images: {
logoLight: "/logo-light.svg",
logoDark: "/logo-dark.svg",
ogImage: "/og-image.png",
},
keywords: [
"Next.js",
"Starter Kit",
"Next.js SaaS Template",
"Next.js Boilerplate",
],
},
};
🌍 Internationalized Metadata
Translation-Based Metadata
NEXTDEVKIT supports internationalized metadata through translation files:
// messages/en.json
{
"app": {
"metadata": {
"title": "NEXTDEVKIT - Modern Next.js Starter Kit",
"description": "A comprehensive Next.js starter kit with authentication, payments, and more"
}
}
}
// messages/zh.json
{
"app": {
"metadata": {
"title": "NEXTDEVKIT - 现代 Next.js 启动套件",
"description": "一个包含认证、支付等功能的综合性 Next.js 启动套件"
}
}
}
Localized Layout Metadata
Generate localized metadata in your layout:
import { metadata } from "@/lib/metadata";
import { getTranslations } from "next-intl/server";
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>;
}): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: "app.metadata" });
return metadata({
title: {
template: `%s | ${t("title")}`,
default: t("title") || "",
},
description: t("description"),
});
}
📄 Page-Specific Metadata
Basic Page Metadata
Add metadata to individual pages:
import { metadata } from "@/lib/metadata";
import { getTranslations } from "next-intl/server";
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: "pricing" });
return metadata({
title: t("title"),
description: t("description"),
image: "/images/pricing-og.png",
keywords: ["pricing", "plans", "subscription", "nextdevkit"],
});
}
export default function PricingPage() {
return (
<div>
<h1>Pricing</h1>
{/* Page content */}
</div>
);
}
Dynamic Page Metadata
Generate metadata for dynamic pages:
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string[]; locale: Locale }>;
}): Promise<Metadata | undefined> {
const { slug, locale } = await params;
const blog = (await getBlogsFromParams(slug)) as any;
if (!blog) {
return {};
}
const t = await getTranslations({ locale, namespace: "blog" });
return metadata({
title: `${blog.title} | ${t("title")}`,
description: blog.description,
keywords: blog.keywords?.split(",") || [],
});
}
🗺️ Sitemap Generation
Automatic Sitemap
NEXTDEVKIT automatically generates sitemaps in src/app/sitemap.ts
.
🤖 Robots.txt Configuration
Robots.txt Setup
Configure robots.txt in src/app/robots.ts
.
🖼️ Open Graph Images
Static OG Images
Place static Open Graph images in the public
directory:
public/
├── og-image.png # Default OG image (1200x630)
├── apple-touch-icon.png # Apple touch icon (180x180)
├── favicon.ico # Favicon
├── favicon-96x96.png # High-res favicon (96x96)
├── favicon.svg # SVG favicon
🔧 Troubleshooting
Common SEO Issues
Missing Meta Tags:
- Ensure
generateMetadata
function is implemented - Check if translations are properly loaded
- Verify metadata function is called correctly
Duplicate Content:
- Set proper canonical URLs
- Use
noindex
for development/staging environments - Implement proper internationalization
Slow Loading:
- Optimize images with Next.js Image component
- Use proper loading strategies
- Implement critical CSS inlining
Poor Core Web Vitals:
- Lazy load non-critical images
- Minimize JavaScript bundle size
- Use efficient caching strategies
SEO Testing Tools
Use these tools to test your SEO implementation:
- Google Search Console: Monitor search performance
- PageSpeed Insights: Check Core Web Vitals
- Lighthouse: Audit SEO and performance
🔗 Related Resources
🎯 Next Steps
Now that you understand the SEO system, explore these related features: