Next.js 15はApp Routerを前提としたフルスタックフレームワークとして完成度が非常に高く、これ一本でフロントエンドからAPI、DBアクセスまで書ける。この記事ではまったくの未経験者を想定し、環境構築から簡単なタスク管理アプリをデプロイ直前まで作る工程を通して、Next.jsの中核概念をまとめて学んでいく。
1. 環境構築とプロジェクト作成
Node.js 20以上がインストール済みである前提で進める。まずはプロジェクトの雛形を作る。
npx create-next-app@latest my-tasks \
--typescript --app --tailwind --eslint --src-dir --import-alias "@/*"
cd my-tasks
npm run dev
http://localhost:3000 にアクセスして初期画面が出れば成功だ。--app を付けるとApp Routerが有効になり、src/app 配下にページやレイアウトを配置していく構成になる。
2. ページとレイアウトの考え方
App Routerでは、ディレクトリ構造がそのままURLになる。例えば src/app/tasks/page.tsx を作れば /tasks としてアクセスできる。
// src/app/tasks/page.tsx
export default function TasksPage() {
return (
<main className="p-8">
<h1 className="text-2xl font-bold">タスク一覧</h1>
<p>ここにタスクを表示する</p>
</main>
);
}
layout.tsx は複数のページで共有するレイアウトを定義する。ヘッダーやナビゲーションはこちらに書く。
3. Server ComponentsとServer Actions
Next.js 15ではデフォルトで全コンポーネントがServer Componentとして動作する。DBアクセスや秘密鍵を扱う処理をクライアントに漏らさず直接書けるのが強みだ。
// src/app/tasks/page.tsx
import { db } from "@/lib/db";
export default async function TasksPage() {
const tasks = await db.task.findMany({ orderBy: { createdAt: "desc" } });
return (
<ul>
{tasks.map((t) => (
<li key={t.id}>{t.title}</li>
))}
</ul>
);
}
フォーム送信はServer Actionsを使えば、API Routeを作らずに関数として直接呼び出せる。
// src/app/tasks/actions.ts
"use server";
import { db } from "@/lib/db";
import { revalidatePath } from "next/cache";
export async function createTask(formData: FormData) {
const title = String(formData.get("title") ?? "").trim();
if (!title) return;
await db.task.create({ data: { title } });
revalidatePath("/tasks");
}
4. Client Componentsとインタラクション
状態管理やイベントハンドリングが必要な部分だけ、ファイル先頭に "use client" を書いてClient Componentにする。この線引きを意識するとバンドルサイズが小さく保てる。
"use client";
import { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>count: {count}</button>;
}
5. データフェッチとキャッシュ
fetch 関数は拡張されており、Next.jsのキャッシュ機構と統合されている。revalidate を指定するとISR相当の挙動になる。
const res = await fetch("https://api.example.com/posts", {
next: { revalidate: 60 },
});
const posts = await res.json();
次のステップ
- PrismaでDBスキーマを定義してSQLiteに保存してみる
- middlewareを使って認証ガードを追加する
- Vercelにデプロイして本番環境で動作確認する
この流れを一周すると、モダンなフルスタック開発の全体像が一気に掴める。