以前は「SEO が必要なら SPA は避ける」が定石でしたが、
Next.js の SSR/SSG が実用段階に入り、その前提が変わりました。
Django と組み合わせるときの構成を整理します。
役割分担
Next.js … 画面の描画(SSR/SSG/CSR を画面ごとに選ぶ)
Django … API、認証、権限、業務ロジック、管理画面
Django の管理画面をそのまま残せるのがこの構成の実利です。
運用者向けの画面を作り直さずに済みます。
画面ごとに描画方法を選ぶ
Next.js の利点は「全部 SSR」ではなく、画面ごとに選べることです。
| 画面 | 方式 | 理由 |
|---|---|---|
| LP・記事 | SSG | 更新頻度が低い。最速で配信できる |
| 商品一覧 | SSR | 在庫が変わる。SEO も要る |
| マイページ | CSR | ログイン必須。SEO 不要 |
ここを一律にすると、どこかで必ず無理が出ます。
認証をどう持つか
分離構成で最も設計が割れるのがここです。実際の判断はこうしています。
同一ドメインで運用できるなら、Cookie セッションのまま
example.com → Next.js
example.com/api/ → Django(リバースプロキシで振り分け)
Django のセッション Cookie がそのまま使えます。
HttpOnly + Secure + SameSite=Lax にしておけば、
トークンを JavaScript から触らせずに済むので、XSS 時の被害が小さくなります。
ドメインが分かれるなら、トークン + リフレッシュ
その場合も、アクセストークンを localStorage に置くのは避けます。
XSS があった瞬間に持ち出されます。可能なら Cookie に寄せます。
CORS と CSRF
同一ドメイン構成にすると CORS の設定自体が不要になります。
これも同一ドメインを勧める理由です。
分離する場合は Django 側で明示的に許可します。
CORS_ALLOWED_ORIGINS = ["https://app.example.com"]
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ["https://app.example.com"]
CORS_ALLOW_ALL_ORIGINS = True は本番では使いません。
ISR を使うときの注意
更新のあった記事だけ再生成する仕組みは強力ですが、
再生成の失敗に気づけない構成になりがちです。
Django 側で更新イベントを記録し、再生成の成否をログに残すようにしています。
この構成を選ばない場合
- 画面数が少ない業務システム
- 納品後に社内の非エンジニアが触る
- 更新が年に数回
この場合は Django だけで完結させたほうが、総コストが確実に低くなります。
まとめ
- 画面ごとに SSG / SSR / CSR を選べることが最大の利点
- 可能なら同一ドメインにして Cookie セッションを使い回す(CORS も不要になる)
- トークンを
localStorageに置かない - 小規模・低更新頻度なら分離しないほうが安い