Next.jsの新しいバージョン(16)の変更点等について

公開日:2025年10月22日(最終更新日:2025年10月23日)

目次

• Next.jsの新しいバージョンの変更点について(2025年10月記載)

• 変更点 1(インストール時の質問)

• 変更点 2(middleware.jsからproxy.jsへ)

• 変更点 3(contextの使い方)

―――――――――――――

• 参考情報 1:Reactサーバーコンポーネントの解説

• 参考情報 2:Reactサーバーコンポーネントを使ったデータ取得の方法

• 参考情報 3:ReactサーバーコンポーネントとReactバージョン19を使ったコードの書き方

Next.jsの新しいバージョン(16)の変更点について

本書は発行時点(2024年9月)での最新バージョンのNext.js(バージョン14)をベースに解説を進めています。しかし、Next.jsは新しいバージョンが定期的にリリースされており、現時点(2025年10月)での最新版はバージョン16です。そのため、本書の説明の通りに下記コマンドでNext.jsをインストールすると、自動でバージョン16がインストールされます。

npx create-next-app next-market

バージョン15および16では多くの変更が加えられたため、バージョン14を使っている本書の通りに進めるとエラーの出る箇所があります。本ページでは以下、変更点と対応策を紹介していきます。

なお、Next.jsバージョン16を使った最終完成見本コードは下記URLにあるので、適宜参考にしてください。

https://github.com/mod728/nextjs-react-book-nextjs-version-16


変更点 1(インストール時の質問)

最新のバージョン16では、上記Next.jsインストールコマンド実行時の質問が大きく変更されています。

本書Chapter 2の「01 Next.jsのインストール」におけるNext.jsのインストール部分の解説は、次のもので読み替えて進めてください。


......それではここ(ダウンロードフォルダ)にNext.jsをインストールしましょう。次のコマンドをターミナルに入力し、「Enter」キーで実行してください。

% npx create-next-app next-market

この「npx」とは、インストールを実行する特別なコマンドで、本書ではここでしか使いません。次の「create-next-app」では、Next.jsのインストールを指定しています。最後の「next-market」はインストールしたフォルダに付ける名前で、ここでは「next-market」としていますが、好きなもので大丈夫です。

ここで次のようなメッセージが出ることがありますが、特に問題ではないので、何もせずに「Enter」キーを押してください。

Need to install the following packages:
    create-next-app@16.0.0
Ok to proceed? (y)

インストールを実行すると質問がいくつか出てきます。一つ目は、インストールするNext.jsの初期設定をどの程度済ませておくか問う質問です。

? Would you like to use the recommended Next.js defaults? › - Use arrow-keys. Return to submit.
    Yes, use recommended defaults
    No, reuse previous settings
❯   No, customize settings
    Choose your own preferences

「TypeScriptやTailwind CSSなども一緒にインストールする(use recommended defaults)」、「前回の設定の再利用(reuse previous settings)」、「自分で決める(customize settings)」という3つの選択肢があります。本書ではミニマムな設定で進めていきたいので、矢印キーで「No, customize settings」を選び、「Enter」キーで実行してください。

次に、Next.jsの初期設定を決める次のような質問が出てきます(2025年10月現在)。

? Would you like to use TypeScript? › No / Yes
? Which linter would you like to use? › - Use arrow-keys. Return to submit.
? Would you like to use Tailwind CSS? › No / Yes
? Would you like to use `src/` directory? › No / Yes
? Would you like to use App Router? (recommended) › No / Yes
? Would you like to customize the default import alias (@/*)? › No / Yes

「Would you like to〜」とは「Do you want〜」の丁寧な聞き方なので、これらの質問は「TypeScriptやTailwind CSSなども一緒にインストールしますか?」と聞いているのだとわかります。

本書では最小限のデフォルト設定で開発を進めたいので、各質問には次のように回答してください。

✔ Would you like to use TypeScript?  → 「No」
✔ Which linter would you like to use?  → 「None」
✔ Would you like to use React Compiler?  → 「Yes」
✔ Would you like to use Tailwind CSS?  →  「No」
✔ Would you like your code inside a `src/` directory?  →  「No」
✔ Would you like to use App Router? (recommended) →  「Yes」
✔ Would you like to use Turbopack? (recommended)  →  「Yes」
✔ Would you like to customize the import alias (`@/*` by default)?  →  「No」

注意して欲しいのは下から3つ目の「App Router」に関する質問です。かならず「Yes」を選択してください。これによって、Next.jsバージョン13以降でデフォルトとなっている「Appフォルダ」が利用できます。

なお、TurbopackとはNext.jsの開発元Vercel社が開発を主導しているバンドラー(開発を高速化するツール)で、バージョン16からはNext.js開発時のデフォルトのバンドラーになっています。またReact Compilerは、Reactのコードを最適化するツールで、これもNext.jsバージョン16から利用できるようになっています。本書ではインストールしてもしなくても構いませんが、今後はReact Compilerの利用が標準になっていくと考えられるので、ここでは「Yes」を選択しています。


変更点 2(middleware.jsからproxy.jsへ)

本書Chapter 4の「04 ユーザーのログイン状態を判定する機能」の項以降、middleware.jsというファイルが登場します。

バージョン16ではファイル名がmiddleware.jsからproxy.jsに変更されたので、proxy.jsという名前でファイルを作ってください。

またそれに合わせて、ファイル内のコードでmiddleware()と書いてある箇所もproxy()に変更してください。

import { NextResponse } from "next/server"

export async function proxy(){         // 「middleware()」から「proxy()」に変更
    return NextResponse.next()
}

変更点 3(contextの使い方)

本書ではバックエンドとフロントエンド両方において、contextというコードを複数の箇所で使っています。Next.jsバージョン16ではcontextの使い方が変更されており、本書の通りに進めるとエラーが発生するので、これから説明する変更をコードに加えてください。


本書ではcontextをURL取得のために使っています。最初に登場するのは、Chapter 3のMongoDBからアイテムを1つ読み取る機能を開発する時です。

本書で使っているバージョン14では、contextの内部へはcontext.params.idのようにダイレクトにアクセスできました。しかしバージョン16ではawaitを使う必要があるため、次のように1行余分に書く必要があります。

// バージョン14(本書)
console.log(context.params.id)

// バージョン16
const params = await context.params
console.log(params.id)

contextの利用時には上記の書き方で対応してください。

以下、本書を終えた時点での完成見本コードを用いて、バージョン16を使った場合に変更すべき箇所を紹介します。変更後のコードは下記URLにあるので、適宜参考にしながら進めてください。

https://github.com/mod728/nextjs-react-book-nextjs-version-16

まずはバックエンド関係のファイルからです。

// app/api/item/readSingle/[id]/route.js(アイテムをひとつ読み取る機能)

import { NextResponse } from "next/server"
import connectDB from "../../../../utils/database"
import { ItemModel } from "../../../../utils/schemaModels"

export async function GET(request, context){
    try{
        await connectDB()
        const params = await context.params                       // 追加
        const singleItem = await ItemModel.findById(params.id)    // 変更
        return NextResponse.json({message: "アイテム読み取り成功(シングル)", singleItem: singleItem})
    }catch{
        ...
// app/api/item/update/[id]/route.js(アイテムの編集機能)

import { NextResponse } from "next/server"
import connectDB from "../../../../utils/database"
import { ItemModel } from "../../../../utils/schemaModels" 

export async function PUT(request, context){
    const reqBody = await request.json() 
    try{
        await connectDB()
        const params = await context.params                         // 追加
        const singleItem = await ItemModel.findById(params.id)      // 変更
        if(singleItem.email === reqBody.email){
            await ItemModel.updateOne({_id: params.id}, reqBody)   // 変更
            return NextResponse.json({message: "アイテム編集成功"})
        }else{
            return NextResponse.json({message: "他の人が作成したアイテムです"})
        }
    }catch{
        ...
// app/api/item/delete/[id]/route.js(アイテムの削除機能)

import { NextResponse } from "next/server"
import connectDB from "../../../../utils/database"
import { ItemModel } from "../../../../utils/schemaModels"

export async function DELETE(request, context){
    const reqBody = await request.json()
    try{
        await connectDB()
        const params = await context.params                       // 追加
        const singleItem = await ItemModel.findById(params.id)    // 変更
        if(singleItem.email === reqBody.email){
            await ItemModel.deleteOne({_id: params.id})           // 変更
            return NextResponse.json({message: "アイテム削除成功"})
        }else{
            return NextResponse.json({message: "他の人が作成したアイテムです"})
        }
    }catch{
        ...

次はフロントエンド関係のファイルです。

// app/item/readSingle/[id]/page.js(アイテムをひとつ読み取るページ)

import Image from "next/image"  
import Link from "next/link" 

const getSingleItem = async(id) => {
    
    ...

}  

const ReadSingleItem = async(context) => {
    const params = await context.params                // 追加
    const singleItem = await getSingleItem(params.id)  // 変更
    return (
        <div className="grid-container-si">
            ...
// app/item/update/[id]/page.js(アイテム編集ページ)

"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation" 
import useAuth from "../../../utils/useAuth"

const UpdateItem = (context) => {
    
    ...

    useEffect(() => {
        const getSingleItem = async() => {           // 「id」を削除
            const params = await context.params      // 追加                                    // ⬇変更
            const response = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/item/readsingle/${params.id}`, {cache: "no-store"})
            const jsonData = await response.json() 
            const singleItem = jsonData.singleItem
            setTitle(singleItem.title)
            setPrice(singleItem.price)
            setImage(singleItem.image)
            setDescription(singleItem.description)
            setEmail(singleItem.email) 
            setLoading(true) 
        }  
        getSingleItem()                         // 「context.params.id」を削除
    }, [context]) 

    const handleSubmit = async(e) => {
        e.preventDefault() 
        const params = await context.params        // 追加 
        try{                                                                               // ⬇変更
            const response = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/item/update/${params.id}`, {
                method: "PUT",
                headers: { 
                    "Accept": "application/json", 
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${localStorage.getItem("token")}`
                },
                ...

// app/item/delete/[id]/page.js(アイテム削除ページ)


"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation" 
import Image from "next/image"   
import useAuth from "../../../utils/useAuth"

const DeleteItem = (context) => {
    
    ...

    useEffect(() => {
        const getSingleItem = async() => {             // 「id」を削除
            const params = await context.params       // 追加                                  // ⬇変更
            const response = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/item/readsingle/${params.id}`, {cache: "no-store"})
            const jsonData = await response.json() 
            const singleItem = jsonData.singleItem
            setTitle(singleItem.title)
            setPrice(singleItem.price)
            setImage(singleItem.image)
            setDescription(singleItem.description)
            setEmail(singleItem.email) 
            setLoading(true)  
        }  
        getSingleItem()                          // 「context.params.id」を削除
    }, [context]) 

    const handleSubmit = async(e) => {
        e.preventDefault() 
        const params = await context.params         // 追加 
        try{                                                                               // ⬇変更
            const response = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/item/delete/${params.id}`, {
                method: "DELETE",
                headers: { 
                    "Accept": "application/json", 
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${localStorage.getItem("token")}`
                },
                ...

参考情報 1:Reactサーバーコンポーネントの解説

Next.jsではReactサーバーコンポーネントがデフォルトのReactコンポーネントになっています。ビギナー向けの本書では深い解説を避けていますが、くわしく知りたい方は下記ページをご覧ください。

Reactサーバーコンポーネントのわかりやすい解説

参考情報 2:Reactサーバーコンポーネントを使ったデータ取得

Reactサーバーコンポーネントを使うと、データの読み取りに関しては、APIサーバーを経由せずにデータベースに直接アクセスをして実行することが可能です。

興味のある方は下記ページをご覧ください。

Reactサーバーコンポーネントを使ったデータ取得の方法

参考情報 3:ReactサーバーコンポーネントとReactバージョン19を使ったコードの書き方

フロントエンド側の編集ページと削除ページを、ReactサーバーコンポーネントおよびReactバージョン19を使って書く方法を参考情報として公開しました。

興味のある方は下記ページをご覧ください。Chapter 8終了時のコードに追加する形で進めています。

ReactサーバーコンポーネントとReactバージョン19を使った削除・編集ページの書き方