AI個人開発の技術スタック

AI個人開発で使うNext.jsとは?

AIがよく提案する技術ですが、すべてのシステムに必要なわけではありません。何が得意で、どこから運用の話になるのかを整理します。

画面とサーバー処理を一つの構成で作る

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 migrate
なぜPrismaではないか:Prismaは独自のクライアントとクエリエンジンを介してSQLを生成するため、遅いクエリを調べるときに「コードのどの書き方が、実際にどんなSQLになっているか」を一段掘り下げて確認する必要があります。AIに性能調査やSQLの実行計画(EXPLAIN)を読ませて改善させる場面では、この一段が調査の速度を落とします。Drizzleはコードとして書いたものがほぼそのままSQLに対応するため、AIも人も実際に発行されるSQLを見失いにくくなります。これはPostgreSQLのスロークエリログ(log_min_duration_statement)を見るときにも効きます。ログに残るのは実際に発行されたSQL文です。Drizzleなら、そのSQLの特徴的な部分(テーブル名やWHERE句の形)でコードベースをそのまま検索すれば、発行元のコードにたどり着けます。Prismaは独自クライアントがSQLを組み立てるため、ログのSQLと手元のコードの見た目が一致せず、発行元を特定しにくいという指摘が以前からありました。Prisma自身もこの点を課題として認識しており、近年のバージョンではSQLにモデル名やアクションを埋め込んだコメントを付与し、専用の画面(Query Insights)で発行元へ逆引きできる機能を追加しています。裏を返せば、Prismaは追跡のために専用の仕組みが必要な一方、Drizzleは追加のツールなしで最初から追跡しやすい、という違いです。Prismaを採用する場合も、マイグレーション方式はプロジェクト内で一つに統一します。

実装と同時にユニットテストを書く

金額計算、入力検証、権限判定などを、Vitestなどで小さな単位に分けてテストします。画面操作はReact Testing Library、主要な利用手順はPlaywrightなどのE2Eテストで補います。

AIへの依頼例:「実装と同時にユニットテストを書き、正常系、境界値、不正入力、権限エラーを確認してください。Lint、型チェック、テストをすべて実行してください」

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.target
PM2という選択肢もある:systemdの代わりに、Node.js専用のプロセスマネージャであるPM2で管理する方法もあります。pm2 start server.js --name my-appのように起動し、ログのローテーションや複数プロセスでのクラスタ実行を簡単に設定できます。一方systemdはOS標準の仕組みだけで完結し、GoのAPIなど他言語のプロセスとも同じ管理方法に揃えられます。この手引ではsystemdを基本にしていますが、Node.js中心の構成ならPM2も有力です。