nero15.dev の技術選定:なぜNext.jsを選んだのか

はじめに
nero15.devは、サッカー情報を中心に技術記事なども配信するメディアプラットフォームです。1から開発するにあたり、技術スタックの選定は重要な決断でした。
本記事では、フロントエンドフレームワークとしてNext.jsを選択した理由と、その判断に至るまでの思考プロセス、そして実際に開発してハマったポイントを共有します。
前提:AI駆動開発という開発スタイル
このプロジェクトはAI駆動開発を前提としています。今後の機能追加や保守においても、AIを活用したコード生成は重要なファクターになると考えています。
実際に業務でAIを使ってコード生成をしてきた経験から言えることは、フロントエンドコードの生成はReactが圧倒的に生成精度が高いという点です。Claude、ChatGPT、GitHub Copilotなど、どのAIツールを使っても、Reactのコンポーネント生成は非常に高品質で、そのまま使えるケースが多い。プロンプトを少し調整するだけで、期待通りのコードが返ってくる。
Vue.jsやSvelteも選択肢としてはありましたが、AIによるコード生成の品質と速度を考えると、React(Next.js)は現時点で最も開発効率が高いフレームワークだと判断しました。特に個人開発で限られた時間の中で開発を進めるには、この「AIとの相性」は無視できない要素でした。
Next.jsを選んだ理由
1. SEO機能の充実度
Next.jsはSEO対策に必要な機能が非常に充実しています。メディアサイトである以上、検索流入は生命線なので、この点は最重要視しました。
Metadata API
App Routerでは、各ページでmetadataオブジェクトをエクスポートするだけで、タイトル、description、OGPタグなどを簡単に設定できます。
export const metadata: Metadata = {
title: 'ミラノダービー | 試合分析',
description: 'ミラノダービーの詳細な戦術分析',
openGraph: {
title: 'ミラノダービー | 試合分析',
description: 'ミラノダービーの詳細な戦術分析',
images: ['/og-image.jpg'],
},
twitter: {
card: 'summary_large_image',
},
}
構造化データ(JSON-LD)のサポート
検索エンジンに記事の構造を正確に伝えるため、JSON-LD形式の構造化データを埋め込むことで、リッチリザルトの表示確率が上がります。
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
author: {
'@type': 'Person',
name: 'nero15',
},
datePublished: post.date,
}
sitemap.xmlとrobots.txtの自動生成
app/sitemap.tsとapp/robots.tsを作成するだけで、動的にサイトマップとrobots.txtを生成できます。記事が増えても自動的に反映されるため、手動管理の必要がありません。
Dynamic OG Image Generation
next/ogを使えば、記事タイトルから動的にOG画像を生成できます。SNSでのシェア時に視覚的に魅力的な画像を自動生成できるのは、メディア運営において大きなメリットです。
2. SSRの必要性
個人的に、このプロジェクトではSSRが必須だと考えていました。
静的生成(SSG)だけでは、記事の更新を即座に反映できません。試合結果や移籍情報など、タイムリーな情報を扱うメディアでは、記事を公開したらすぐに検索エンジンにクロールされ、インデックスされる必要があります。毎回ビルドを走らせるのは現実的ではありません。
Next.jsのSSRでは:
- ページリクエスト時にサーバー側でReactコンポーネントをレンダリング
- HTMLとして完全なコンテンツをクローラーに返す
- JavaScriptが無効でもコンテンツが表示される
- Core Web Vitals(特にLCP)の改善に寄与
ISRについては、正直なところあまり知見がなかったため、今回はリリースまでの開発速度を優先するために深く調査しませんでした。これは今後検討したい課題です。
SSGとSSRを併用できるのもNext.jsの強みです。トップページはSSG、記事詳細ページはSSRと、ページごとに最適なレンダリング方法を選択できるのは、パフォーマンスとSEOのバランスを取る上で重要でした。
3. GCP Cloud Runとの相性
インフラにはGCPのCloud Runを採用しました(この選択理由については別記事で書く予定です)。
Next.jsはコンテナ化が容易で、Cloud Runとの相性が非常に良いです。
- Dockerfile一つでデプロイ可能:
next buildとnext startでSSRアプリケーションをコンテナとして起動 - オートスケーリング:トラフィック急増時も自動でスケール。試合速報のような瞬間的なアクセス集中にも対応できる
- コールドスタート時間の短縮:最近のNext.jsとCloud Runの組み合わせは、コールドスタート時間が大幅に改善されている
- コスト効率:アクセスがない時はスケールダウンし、従量課金なのでコストを抑えられる
Vercelも検討しましたが、Cloud Runの方が:
- 他のGCPサービス(Cloud SQL、Cloud Storageなど)との統合がスムーズ
- インフラ全体をGCPで統一できる
- 料金体系が明確でスケールしやすい
という点で優れていると判断しました。個人開発でも将来的なスケールを見据えた時、GCPの方が柔軟性が高いと感じています。
4. ファイルベースルーティングとApp Router
app/posts/[slug]/page.tsxのような形で、直感的にルーティングを定義できます。App Routerの導入により、Reactの最新機能(Server Components、Streaming SSRなど)も活用可能です。
特に、AIにコードを生成させる際、「このパスに新しいページを作って」という指示だけで、適切なディレクトリ構造とファイルを生成してくれるのは、開発速度の面で大きなメリットでした。
5. 豊富なエコシステム
マークダウン記事を扱うための便利なライブラリが充実しています:
gray-matter: frontmatterのパースremark/rehype: マークダウンのHTML変換と拡張next-mdx-remote: MDXのサポート
これらをNext.jsと組み合わせることで、柔軟な記事管理システムを短期間で構築できました。AIに「こういう記事システムを作りたい」と伝えれば、これらのライブラリを組み合わせた実装を提案してくれます。
ハマりポイント:ビルド時の環境変数
実際に開発していて、一番ハマったのがNext.jsの環境変数の扱いです。
正直に言うと、私は本職がバックエンドエンジニアで、Next.jsを使って一から構築した経験はありませんでした。これまでのキャリアでNext.jsをガッツリ触ったことがなく、今回が初めての本格的な構築でした。
何にハマったか
Next.jsは**ビルド時に環境変数を埋め込む(インライン化する)**という仕様になっています。
具体的には:
next build実行時にprocess.env.NEXT_PUBLIC_*などの環境変数が、JavaScriptバンドルに文字列として直接埋め込まれる- ビルド後のアプリケーションは、もはや環境変数を参照しない(すでに固定値になっている)
- Cloud Runなどのインフラ側でいくら環境変数を設定しても、ビルド済みのコードには反映されない
これはwebpack DefinePluginによる置換処理で、process.env.NEXT_PUBLIC_API_URLのような記述が、ビルド時に"https://api.example.com"という文字列リテラルに置き換わってしまうのです。
何が問題だったか
通常のバックエンド開発では:
- アプリケーションをビルド
- 本番環境で環境変数を設定
- アプリケーションを起動すると、ランタイムで環境変数を読み込む
という流れが当たり前です。しかしNext.jsでは、ビルド時に環境変数が決まってしまうため:
- CI/CDでDocker imageをビルド
- Cloud Runにデプロイし、環境変数を設定
- 起動しても環境変数が反映されない...
という状況に陥りました。インフラ側の設定をいくら見直しても解決せず、かなり時間を溶かしました。
どう解決したか
結論として、GitHub Actionsのビルドステップで環境変数をセットするという対応をしました。
具体的には、GitHub Actionsのワークフロー内で:
- GitHub Secretsから環境変数を取得
docker build時に--build-argで環境変数を渡す- Dockerfile内で
ARGとして受け取り、ENVとして設定 next build実行時に環境変数が埋め込まれる
という流れにしています。
この辺の具体的な実装については、別途記事にする予定です。GitHub ActionsとCloud Runを組み合わせたCI/CD環境の構築は、意外とハマりどころが多いので、同じ境遇の人の参考になればと思っています。
学んだこと
Next.jsの環境変数は、Reactアプリケーション特有の「ビルド時最適化」の産物です。セキュリティ面でも、クライアント側で動くコードに秘密情報を埋め込むリスクを減らすための設計になっています。
バックエンド開発の常識が通用しない部分があり、フロントエンド(特にReactエコシステム)の特性を理解する良い機会になりました。
実際に使ってみての感想
良かった点
- AIによるコード生成が非常にスムーズで、開発速度が格段に上がった
- 「このページでSSRを使って〜」という指示だけで、適切なコードが生成される
- SEO関連のベストプラクティスがフレームワークレベルで組み込まれている
- TypeScriptの型サポートが優秀で、型安全性を保ちながら開発できた
- マークダウンベースの記事管理が想像以上に快適
課題や工夫した点
- App Routerはまだ新しく、日本語の情報が少ない部分もある(英語ドキュメントを読む機会が増えた)
- ビルド時の環境変数問題は、フロントエンド経験が少ないと確実にハマる
- SSRのパフォーマンスチューニングには注意が必要
- Cloud Runでのコンテナ最適化(レイヤーキャッシュなど)も今後の課題
まとめ
nero15.devの開発において、Next.jsは最適な選択でした。
特に:
- AI駆動開発との相性:Reactベースで、AIによるコード生成精度が高く、開発速度が大幅に向上
- SEO機能の充実:Metadata API、構造化データ、OG画像生成など、メディアサイトに必要な機能が揃っている
- SSR対応:タイムリーな情報配信に必須の機能
- Cloud Runとの相性:コンテナ化が容易で、インフラ戦略と合致
一方で、フロントエンド特有の「ビルド時最適化」の仕組みは、バックエンドエンジニア視点では直感的でない部分もありました。しかし、これらの学びも含めて、Next.jsを選んで良かったと感じています。
最終更新: 2025年10月4日
