画面とサーバー処理を一つの構成で作る
Next.jsはReactを基盤としたWebアプリケーションフレームワークです。画面、入力フォーム、サーバー側の処理、データ取得を同じプロジェクトで構成できます。現在の新規開発ではApp Routerが中心です。
Next.jsが向く場合、向かない場合
向いている
ブラウザで使う業務アプリ、ログイン付き画面、APIと画面を一緒に作るシステム。
重すぎることがある
一度だけ使う集計、単純なバッチ処理、静的な数ページだけのサイト。
「AIが提案したから」ではなく、利用者がブラウザで継続利用するアプリかどうかで判断します。
PostgreSQLとは別の役割
Next.jsはアプリ、PostgreSQLはデータ保管を担当します。この手引の構成例では、SQLに近いTypeScriptでクエリを書けるDrizzle ORMと、変更用SQLを生成・管理するDrizzle Kitを組み合わせます。接続情報は環境変数で渡し、秘密情報や本番データをGitへ保存してはいけません。
テーブルの定義はTypeScriptのコードとして書きます。
// schema.ts
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const customers = pgTable("customers", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull(),
createdAt: timestamp("created_at").defaultNow(),
});クエリもSQLに近い書き方のまま組み立てます。
import { db } from "./db";
import { customers } from "./schema";
import { eq } from "drizzle-orm";
const customer = await db
.select()
.from(customers)
.where(eq(customers.email, email));スキーマを変更したら、差分からマイグレーションSQLを生成し、内容を確認してから適用します。
npx drizzle-kit generate
npx drizzle-kit migratelog_min_duration_statement)を見るときにも効きます。ログに残るのは実際に発行されたSQL文です。Drizzleなら、そのSQLの特徴的な部分(テーブル名やWHERE句の形)でコードベースをそのまま検索すれば、発行元のコードにたどり着けます。Prismaは独自クライアントがSQLを組み立てるため、ログのSQLと手元のコードの見た目が一致せず、発行元を特定しにくいという指摘が以前からありました。Prisma自身もこの点を課題として認識しており、近年のバージョンではSQLにモデル名やアクションを埋め込んだコメントを付与し、専用の画面(Query Insights)で発行元へ逆引きできる機能を追加しています。裏を返せば、Prismaは追跡のために専用の仕組みが必要な一方、Drizzleは追加のツールなしで最初から追跡しやすい、という違いです。Prismaを採用する場合も、マイグレーション方式はプロジェクト内で一つに統一します。実装と同時にユニットテストを書く
金額計算、入力検証、権限判定などを、Vitestなどで小さな単位に分けてテストします。画面操作はReact Testing Library、主要な利用手順はPlaywrightなどのE2Eテストで補います。
GA4はレイアウトに1つ足すだけで仕込める
アクセス解析には、Next.js公式の@next/third-partiesパッケージを使うと、手作業でのタグ埋め込みより簡単に導入できます。
npm install @next/third-partiesルートレイアウトにGoogleAnalyticsコンポーネントを1つ置くだけで、全ページに計測タグが入ります。
// app/layout.tsx
import { GoogleAnalytics } from "@next/third-parties/google";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja">
<body>{children}</body>
<GoogleAnalytics gaId="G-XXXXXXXXXX" />
</html>
);
}App Router内でのページ遷移(クライアント側のルーティング)も自動でページビューとして送信されるため、遷移ごとにイベントを送る処理を自分で書く必要はありません。読み込みはページのハイドレーション後に行われ、初期表示の速度にはほとんど影響しません。
本番は開発サーバーのまま公開しない
本番用にビルドしたNext.jsの成果物をLinuxサーバーへ配置し、Node.jsサービスとして常駐させます。アプリを直接公開せず、前段にリバースプロキシを置く構成が基本です。next buildをoutput: "standalone"設定で実行すると、依存パッケージを含めた最小構成のserver.jsが生成され、サーバー側にnode_modules全体を持ち込まずに配置できます。
常駐のさせ方はsystemdが基本です。
[Unit]
Description=my-app
After=network.target
[Service]
Type=simple
WorkingDirectory=/srv/my-app/current
ExecStart=/usr/bin/node server.js
Restart=on-failure
Environment=NODE_ENV=production
Environment=PORT=3000
[Install]
WantedBy=multi-user.targetpm2 start server.js --name my-appのように起動し、ログのローテーションや複数プロセスでのクラスタ実行を簡単に設定できます。一方systemdはOS標準の仕組みだけで完結し、GoのAPIなど他言語のプロセスとも同じ管理方法に揃えられます。この手引ではsystemdを基本にしていますが、Node.js中心の構成ならPM2も有力です。