🚀

Next.js v16が正式リリースしたので、プロジェクトをそれぞれ作って比較してみた!

に公開

本記事のサマリ

Next.js v16がリリースされたので、実際にv15とv16でプロジェクトを作って生成されるファイルを比較してみました。Turbopackがデフォルトになったこと、ESLint設定が新しい形式に対応したことなど細かい変更はいくつかありますが、個人的に一番注目したのは型安全なルーティングシステムです。ルート定義が自動生成されることで、typoによるバグや、存在しないパスへのリンクミスをコンパイル時に検出できるようになります。移行を検討している方の参考になれば幸いです。

※今回試したコードは以下のリポジトリで公開しています。

https://github.com/toto-inu/lab-202510-nextjs-versionup/tree/project-start

Next.js v16がリリースされた

2025年10月21日、Next.js v16が正式にリリースされました。

https://nextjs.org/blog/next-16

公式ブログを見ると、型安全性の向上やビルドツールの改善が主な内容のようです。ただ、リリースノートを読んだだけでは実際どの程度変わっているのか掴みづらかったので、v15とv16でそれぞれ新規プロジェクトを作成し、生成されるファイルを比較してみることにしました。

セットアップから変わっている

まずプロジェクト作成時の挙動から違いがありました。v15では、TypeScript使うかどうか、ESLintどうするか、Tailwind CSS入れるか、App Router使うか、Turbopackはどうするか……といった質問が順番に出てきて、それぞれ答えていく必要がありました。

v16ではこのあたりがシンプルになっています。

✔ What is your project named? … .
? Would you like to use the recommended Next.js defaults? › - Use arrow-keys. Return to submit.
❯   Yes, use recommended defaults - TypeScript, ESLint, Tailwind CSS, App Router, Turbopack
    No, reuse previous settings
    No, customize settings

「推奨デフォルトを使用」を選べば、TypeScript、ESLint、Tailwind CSS、App Router、Turbopackすべて込みで一発セットアップが完了します。カスタマイズしたい場合は従来通り細かく設定できるので、選択の余地は残しつつ、デフォルトで良い場合は手間が省けます。個人的には毎回似たような選択をしていたので、このくらいシンプルな方がありがたいです。

package.json:Turbopackがデフォルトになった

生成されたpackage.jsonを見比べると、scriptsの書き方が変わっていることに気づきます。

v15では --turbopackフラグが明示的に付いていました。

"scripts": {
  "dev": "next dev --turbopack",
  "build": "next build --turbopack"
}

v16では以下のようにフラグがなくなっています。

"scripts": {
  "dev": "next dev",
  "build": "next build"
}

つまり、Turbopackがデフォルトバンドラーになったということです。長らくベータ扱いだったTurbopackが正式採用されたのは、安定性や互換性の検証が進んだ結果だと思われます。依存関係を見ると、Reactが19.1.0から19.2.0に上がっていたり、@eslint/eslintrcパッケージが削除されていたりと、細かな調整もいくつか入っています。

TypeScript設定:JSX変換の方式が変わった

tsconfig.jsonにも変更が入っています。特に気になったのは、jsx設定が "preserve"から "react-jsx"に変わっている点です。

// v15
"jsx": "preserve"

// v16  
"jsx": "react-jsx"

https://www.typescriptlang.org/docs/handbook/jsx.html

TypeScriptの公式ドキュメントによると、"preserve"はJSXをそのまま残して別のツール(例えばBabel)に処理を任せるモードで、"react-jsx"はReact 17で導入された新しいJSX変換を使うモードです。新しい変換では import React from 'react'が不要になり、バンドルサイズが減ってパフォーマンスも改善されます。

https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

Reactの公式ブログでも新しいJSX変換の利点が詳しく説明されています。設定ファイルの一行が変わっただけに見えますが、ビルドの裏側ではそれなりに大きな変更が走っているはずです。

それから、include配列に .next/dev/types/**/*.ts**/*.mtsが追加されています。開発時の型定義やESモジュール形式の型定義にもきちんと対応するための措置だと思われます。細かいですが、型チェックの精度が上がることで、開発中に気づけるエラーが増えるのはありがたいです。

ESLint設定:Flat Configへ完全移行

ESLint周りの変更は、技術的な方向性がよく見える部分です。

https://eslint.org/docs/latest/use/configure/configuration-files

ESLint v9から、従来の .eslintrc形式に代わって「Flat Config」という新しい設定形式が標準になりました。

v15では、Flat Configを使うために @eslint/eslintrcFlatCompatを介して互換性を保つ必要がありました。

// v15のeslint.config.mjs
import { FlatCompat } from "@eslint/eslintrc";

const compat = new FlatCompat({
  baseDirectory: __dirname,
});

const eslintConfig = [
  ...compat.extends("next/core-web-vitals", "next/typescript"),
  // ...
];

v16では完全にネイティブなFlat Config形式になっています。

// v16のeslint.config.mjs  
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

const eslintConfig = defineConfig([
  ...nextVitals,
  ...nextTs,
  globalIgnores([
    ".next/**",
    "out/**", 
    "build/**",
    "next-env.d.ts",
  ]),
]);

互換レイヤーが不要になったことで、設定がすっきりして読みやすくなりました。ESLintの最新機能をそのまま使える環境になったのは地味に嬉しいところです。

型安全なルーティングが自動生成される

今回の比較で一番良いなと感じたのは、プロジェクト作成直後に .next/dev/types/routes.d.tsというファイルが自動生成されていたことです。

// .next/dev/types/routes.d.ts
type AppRoutes = "/"
type PageRoutes = never
type LayoutRoutes = "/"
type RedirectRoutes = never  
type RewriteRoutes = never
type Routes = AppRoutes | PageRoutes | LayoutRoutes | RedirectRoutes | RewriteRoutes

interface ParamMap {
  "/": {}
}

export type ParamsOf<Route extends Routes> = ParamMap[Route]

declare global {
  interface PageProps<AppRoute extends AppRoutes> {
    params: Promise<ParamMap[AppRoute]>
    searchParams: Promise<Record<string, string | string[] | undefined>>
  }

  type LayoutProps<LayoutRoute extends LayoutRoutes> = {
    params: Promise<ParamMap[LayoutRoute]>
    children: React.ReactNode
  } & {
    [K in LayoutSlotMap[LayoutRoute]]: React.ReactNode
  }
}

このファイルがあることで、存在しないパスへのリンクはコンパイルエラーになりますし、動的ルートのパラメータも型推論が効くようになります。

これまで、ルーティング周りは文字列リテラルに頼る部分が多く、typoやリファクタリングの見落としでランタイムエラーになることがよくありました。型でガードできるようになったことで、実行前に問題を検出できる範囲が広がります。特に大きめのプロジェクトでは効果が大きそうですね!

その他の細かな変更点

型安全ルーティング以外にも、細かい変更がいくつかあります。

PostCSS設定は、プラグインの指定方法が配列からオブジェクトになりました。

// v15
const config = {
  plugins: ["@tailwindcss/postcss"],
};

// v16
const config = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

これで、プラグインに個別のオプションを渡しやすくなりました。些細な変更に見えますが、カスタマイズの幅が広がったのは地味に便利です。

next-env.d.tsも、型参照が /// <reference path="..." />から import文に変わっています。ESモジュールの標準的な書き方に寄せてきたということでしょう。

それから本筋のアプデとは別ですが、デフォルトで生成されるページコンポーネントのデザインも変わっていました。v15は手順書っぽいレイアウトでしたが、v16ではもう少しシンプルな見た目になっています。CSS GridからFlexboxベースに変更されていて、最近のWebデザインのトレンドを意識している印象です。

パフォーマンスについては今後検証したい

今回は生成されるファイルの比較が中心だったので、実際の開発サーバー起動時間やビルド速度の測定は行いませんでした。Turbopackがデフォルトになったことで体感速度は上がるはずですが、具体的な数値は次回以降の記事で検証してみようと思います。

https://nextjs.org/docs

公式ドキュメントによると、v16ではCache ComponentsとPartial Pre-Rendering(PPR)という新しいキャッシュモデルも導入されているようです。従来のISRとは異なるアプローチらしく、より柔軟なコンテンツ配信が可能になるとのこと。この辺りも実際に試してパフォーマンスデータを取ってみたいところです。

まとめ

v15とv16でプロジェクトを作成して比較してみた結果、セットアップの簡素化、Turbopackのデフォルト化、ESLint設定のFlat Config対応、そして型安全なルーティングシステムの導入など、複数の変更が入っていることが分かりました。

個人的に一番影響が大きいと感じたのは型安全ルーティングです。ルート定義が自動生成され、コンパイル時にパスのtypoやミスを検出できるようになったのは、開発の安心感を大きく高めてくれます!

既存プロジェクトの移行については、ESLint設定やTypeScript設定が変わっているため、プロジェクトの規模次第では影響範囲が広くなる可能性があります。まずは新規プロジェクトで試してみて、感触を確かめてから既存プロジェクトの移行を検討するのが良さそうです。

次回は、v16で導入されたCache ComponentsとPPRを使って、実際にどの程度パフォーマンスが改善されるのかを検証してみたいと思います。

株式会社StellarCreate | Tech blog📚

Discussion