Next.js 15で実現する最新SEO戦略 | 検索順位を上げる実装テクニック
9 min read
Next.jsSEOApp RouterCore Web Vitals構造化データ
はじめに
Next.js 15のApp Routerは、SEOに最適化された現代的なWebアプリケーションを構築するための強力な機能を提供しています。本記事では、実際に検索順位を上げるための具体的な実装テクニックを紹介します。
なぜNext.js 15なのか?
SPAの課題
従来のReact SPAでは、以下のSEO課題がありました:
- 初回レンダリングが遅い → Googleのクローラーが正しくコンテンツを認識できない
- Metadataの動的生成が困難 → OGP画像が正しく表示されない
- JavaScriptに依存 → JavaScript無効環境で何も表示されない
Next.js 15の解決策
| 課題 | Next.js 15の解決策 |
|---|---|
| 初回レンダリング | Server-Side Rendering (SSR) |
| Metadata生成 | generateMetadata API |
| JS依存 | サーバーコンポーネント |
| ルーティング | ファイルベースの直感的なルーティング |
1. Metadata APIで完璧なSEO設定
基本的な実装
// app/page.tsx
import { Metadata } from 'next'
export const metadata: Metadata = {
title: '株式会社ジェレオシステムズ | AI・システム開発・クラウド構築',
description: '大阪を拠点に、生成AI導入、システム開発、クラウド構築を提供する技術専門企業です。',
keywords: 'AI導入,システム開発,クラウド,大阪,DX',
// OpenGraph設定
openGraph: {
title: '株式会社ジェレオシステムズ',
description: 'AI・システム開発のプロフェッショナル',
url: 'https://www.jereo.co.jp',
type: 'website',
images: [
{
url: '/og-image.png',
width: 1200,
height: 630,
alt: 'Jereo Systems',
},
],
},
// Twitter Card設定
twitter: {
card: 'summary_large_image',
title: '株式会社ジェレオシステムズ',
description: 'AI・システム開発のプロフェッショナル',
images: ['/og-image.png'],
},
// robots設定
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
},
},
// Canonical URL
alternates: {
canonical: 'https://www.jereo.co.jp',
},
}動的Metadataの生成
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: post.title,
description: post.description,
keywords: post.tags.join(', '),
openGraph: {
title: post.title,
description: post.description,
url: `https://www.jereo.co.jp/blog/${post.slug}`,
type: 'article',
publishedTime: post.date,
authors: [post.author],
images: [post.ogImage],
},
}
}ポイント:
- ページごとに異なるMetadataを設定
- OG画像は1200x630pxで作成
- descriptionは120-160文字が最適
2. 構造化データで検索結果を強化
Organization Schema(企業情報)
// components/structured-data/OrganizationSchema.tsx
export function OrganizationSchema() {
const schema = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: '株式会社ジェレオシステムズ',
url: 'https://www.jereo.co.jp',
logo: 'https://www.jereo.co.jp/logo.png',
contactPoint: {
'@type': 'ContactPoint',
telephone: '+81-6-XXXX-XXXX',
contactType: 'Customer Service',
areaServed: 'JP',
availableLanguage: 'Japanese',
},
address: {
'@type': 'PostalAddress',
addressCountry: 'JP',
addressRegion: '大阪府',
addressLocality: '大阪市',
},
sameAs: [
'https://twitter.com/jereosystems',
'https://www.linkedin.com/company/jereosystems',
],
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}Article Schema(ブログ記事)
// components/structured-data/ArticleSchema.tsx
interface ArticleSchemaProps {
title: string
description: string
datePublished: string
author: string
imageUrl: string
}
export function ArticleSchema(props: ArticleSchemaProps) {
const schema = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: props.title,
description: props.description,
image: props.imageUrl,
datePublished: props.datePublished,
author: {
'@type': 'Organization',
name: props.author,
},
publisher: {
'@type': 'Organization',
name: '株式会社ジェレオシステムズ',
logo: {
'@type': 'ImageObject',
url: 'https://www.jereo.co.jp/logo.png',
},
},
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}BreadcrumbList Schema(パンくずリスト)
export function BreadcrumbSchema({ items }: { items: Array<{name: string, url: string}> }) {
const schema = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}効果:
- Google検索結果でリッチスニペット表示
- CTR(クリック率)が平均20-30%向上
- 検索順位の向上に寄与
3. sitemap.xmlとrobots.txtの動的生成
sitemap.xmlの実装
// app/sitemap.ts
import { MetadataRoute } from 'next'
import { getAllPosts } from '@/lib/blog'
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://www.jereo.co.jp'
// 静的ページ
const staticPages = [
{
url: baseUrl,
lastModified: new Date(),
changeFrequency: 'daily' as const,
priority: 1.0,
},
{
url: `${baseUrl}/services/ai-dx`,
lastModified: new Date(),
changeFrequency: 'weekly' as const,
priority: 0.9,
},
// ... 他のページ
]
// 動的ページ(ブログ記事)
const posts = getAllPosts()
const blogPages = posts.map((post) => ({
url: `${baseUrl}/blog/${post.slug}`,
lastModified: new Date(post.date),
changeFrequency: 'monthly' as const,
priority: 0.7,
}))
return [...staticPages, ...blogPages]
}robots.txtの実装
// app/robots.ts
import { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/'],
},
{
userAgent: 'Googlebot',
allow: '/',
},
],
sitemap: 'https://www.jereo.co.jp/sitemap.xml',
}
}4. Core Web Vitalsの最適化
重要な3つの指標
| 指標 | 目標値 | 説明 |
|---|---|---|
| LCP (Largest Contentful Paint) | < 2.5秒 | メインコンテンツの表示速度 |
| FID (First Input Delay) | < 100ms | 最初の入力への応答速度 |
| CLS (Cumulative Layout Shift) | < 0.1 | レイアウトの安定性 |
LCP改善のテクニック
1. 画像の最適化
// Next.js Imageコンポーネントの活用
import Image from 'next/image'
export function HeroImage() {
return (
<Image
src="/hero.jpg"
alt="Hero Image"
width={1200}
height={630}
priority // ファーストビューの画像はpriorityを指定
quality={85}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
)
}2. フォントの最適化
// app/layout.tsx
import { Noto_Sans_JP } from 'next/font/google'
const notoSansJP = Noto_Sans_JP({
weight: ['400', '700'],
subsets: ['latin'],
display: 'swap', // FOUTを防ぐ
preload: true, // プリロードで高速化
})
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja" className={notoSansJP.className}>
<body>{children}</body>
</html>
)
}FID改善のテクニック
動的importで必要なコードのみ読み込み
import dynamic from 'next/dynamic'
// モーダルは使用時のみ読み込み
const Modal = dynamic(() => import('@/components/Modal'), {
loading: () => <p>Loading...</p>,
})
export function MyComponent() {
const [showModal, setShowModal] = useState(false)
return (
<>
<button onClick={() => setShowModal(true)}>Open Modal</button>
{showModal && <Modal />}
</>
)
}CLS改善のテクニック
画像サイズを明示的に指定
// ❌ 悪い例(CLSが発生)
<img src="/banner.jpg" alt="Banner" />
// ✅ 良い例(CLSを防ぐ)
<Image
src="/banner.jpg"
alt="Banner"
width={1200}
height={400}
/>5. 実装チェックリスト
必須項目
-
generateMetadataで全ページにMetadata設定 -
sitemap.xmlの動的生成 -
robots.txtの設定 - Organization Schemaの実装
- Next.js Imageコンポーネントの使用
- フォントの最適化(
display: swap) - Canonical URLの設定
- OGP画像(1200x630px)の作成
推奨項目
- Article Schemaの実装(ブログ記事)
- BreadcrumbList Schemaの実装
- 動的importの活用
- Google Analyticsの設定
- Google Search Consoleへの登録
-
loading.tsxでスケルトンUI実装 -
error.tsxでエラーハンドリング
効果測定の方法
1. Google Search Console
確認すべき指標:
- 検索クエリ数の増加
- 平均掲載順位の改善
- クリック率(CTR)の向上
2. PageSpeed Insights
目標スコア:
- Mobile: 90以上
- Desktop: 95以上
3. Lighthouse
# コマンドラインでLighthouseを実行
npm install -g lighthouse
lighthouse https://www.jereo.co.jp --viewまとめ
Next.js 15でSEOを最適化するための5つのポイント:
- Metadata API - ページごとに最適化されたMetadataを設定
- 構造化データ - リッチスニペットで検索結果を強化
- sitemap/robots - クローラーが効率的にサイトを巡回できるように
- Core Web Vitals - ユーザー体験を最優先に最適化
- 継続的な測定 - Google Search ConsoleとLighthouseで効果を確認
重要なのは、「技術的SEO」と「コンテンツの質」の両立です。
次のステップ
株式会社ジェレオシステムズでは、Next.jsを活用したSEO最適化サイトの構築を支援しています。
無料相談受付中:
- サイト診断(現状分析)
- SEO改善提案
- Next.js移行支援
関連記事: