Next.js 16でStripeの決済機能を実装していたところ、redirectToCheckoutが動かないことに気づきました。
今回は、Checkout Session を使った新しいリダイレクト方法をまとめます。
開発環境
- Next.js 16.1.1
- React 19.2.3
- stripe 20.1.0
- TypeScript 5
原因
redirectToCheckoutの非推奨化
StripeのredirectToCheckoutは 2025年9月にサポートが終了 しました。
代わりに Checkout Sessionを作成し、そのURLにリダイレクトする方法が推奨されています。
サーバー側でリダイレクトできない
最初はNextResponse.redirect()でリダイレクトしようとしましたが、クライアント側でレスポンスをJSONとして受け取れません。
そのためURLをJSON形式で返し、クライアント側でリダイレクトする必要がありました。
解決方法
API側の実装
Route HandlerでCheckout Sessionを作成し、URLをJSONで返します。
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
// Next.js 15以降、paramsは Promise型 のため await が必要
const { id } = await params;
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: id, quantity: 1 }],
success_url: `${process.env.NEXT_PUBLIC_BASE_URL}/success`,
cancel_url: `${process.env.NEXT_PUBLIC_BASE_URL}/cancel`,
});
return NextResponse.json({ url: session.url });
}
Next.js 15 以降ではparamsが Promise 型になったため、awaitで展開する必要があります。
// Next.js 14以前の書き方(エラーになる)
const priceId = params.priceId;
// Next.js 15以降
const { priceId } = await params;
クライアント側の実装
APIから取得したURLにwindow.location.hrefでリダイレクトします。
'use client';
export const CheckoutButton = ({ id }: { id: string }) => {
const handleCheckout = async () => {
const response = await fetch(`/api/checkout/${id}`);
const { url } = await response.json();
// Stripeの決済ページ(Checkout SessionのURL)へ遷移
window.location.href = url;
};
return <button onClick={handleCheckout}>購入する</button>;
};
まとめ
redirectToCheckoutの代わりに、以下の流れで実装し動作することを確認しました。
- API側でCheckout Sessionを作成し、URLをJSONで返す
- クライアント側で
window.location.hrefを使ってリダイレクトする
参考サイト
Stripe - Checkout Sessions
Stripe - redirectToCheckoutのサポート終了
Stripe - Checkout セッションを作成する