---
title: "Remix SPAモード（React Router v8）とAmplify Gen 2の構成手順｜amplify.ymlとリライト設定"
url: "https://www.issoh.co.jp/tech/details/2281/"
published: 2024-05-27
updated: 2026-10-12
categories: ["AWS"]
publisher: "株式会社一創"
---

# Remix SPAモード（React Router v8）とAmplify Gen 2の構成手順｜amplify.ymlとリライト設定

Remix の SPA モードで作ったフロントエンドを AWS Amplify Gen 2 につなぐ構成は、2024 年の記事のまま組むと 3 か所で止まります。Gen 1 の `amplify init` は新規アカウントで通らず、`npm i remix` で入るのは React を使わない Remix 3 になり、Amplify Hosting は `amplify_outputs.json` が無いままフロントをビルドして失敗します。この記事では 2026 年 10 月時点の公開版と React Router 8.4.0 での実測をもとに、接続コード、`amplify.yml`、リライト規則、この構成を選ばない方がよい条件までを順に示します。

## まとめ：Remix SPAモードとAmplify Gen 2を組む前に決める5点

| 決めること        | 2026年10月時点の結論               | 理由                           |
| ------------ | --------------------------- | ---------------------------- |
| フロントの系列      | React Router v8（8.4.0）      | v2 の後継。remix 3.0.0 は別系列      |
| バックエンドの世代    | Gen 2 一択                    | Gen 1 は新規受付停止・2027-05-01 EOL |
| データ取得        | clientLoader / clientAction | root 以外の loader はビルドで失敗      |
| Hosting のビルド | backend で pipeline-deploy   | outputs をビルド前に生成             |
| 配信とリライト      | build/client ＋ 拡張子除外の200    | build/server は配信しない          |

この 5 点が決まれば、残りは設定ファイルの書き方だけです。以下、それぞれの根拠とコードを示します。

## 2026年10月時点の前提：Remix 3正式版とAmplify Gen 1の新規停止

Remix 2.5.0 で SPA モードが入ったのが 2024 年 1 月 11 日、Amplify Gen 2 の一般提供が 2024 年 5 月 6 日です。この組み合わせの解説が増えたのはその直後で、両端ともその後に大きく動きました。

### remix 3.0.0とReact Router v8の系列の違い

npm の `remix` パッケージは 2026 年 10 月 1 日に [3.0.0 が latest](https://www.npmjs.com/package/remix) になりました。依存 48 件はすべて `@remix-run/*` で React を含まず、engines は `node>=24.3.0` です。Remix 3 は独自のコンポーネントモデルを持つ別系列で、SPA モードも `ssr:false` もありません。中身は[Remix 3のコンポーネントとは？3.0正式版のhandle・mixの書き方と@remix-run/ui](/tech/details/10504/)で扱っています。

v2 のアプリは `@remix-run/react` や `@remix-run/dev` に依存しているため、勝手に 3.0.0 へ上がることはありません。確認時点の v2 系の公開版は 2.17.5 です。v2 の実質的な後継は React Router で、`react-router` の latest は 8.4.0（2026 年 9 月 15 日）、v7 系は 7.18.4 です。v8 は engines が `node>=22.22.0`、peerDependencies が `react>=19.2.7` なので、Node.js 22.0〜22.21 で動いている CI はフロントを上げた時点で止まります。新規なら `npx create-react-router@latest` から始めてください。SPA モードの仕様と v2 からの移行判断は[Remix SPAモードとは？ssr:falseの設定と制約、React Router移行の判断](/tech/details/3840/)にまとめています。

### Amplify Gen 1の新規受付停止とamplify initの拒否

AWS は Amplify CLI のリポジトリで Gen 1 の扱いを告知しています。「Starting May 1, 2026, Gen 1 backends will receive only critical bug fixes and security patches and will reach end of life on May 1, 2027.」（[aws-amplify/amplify-cli issue #14881](https://github.com/aws-amplify/amplify-cli/issues/14881)、2026 年 5 月 14 日）。

紛らわしいのは、`@aws-amplify/cli` 14.5.1（2026 年 6 月 25 日）が npm に deprecated の印なしで残っていることです。インストールはできます。ただし同梱の `@aws-amplify/amplify-provider-awscloudformation@8.11.19` に `lib/gen1-new-customer-restriction.js` が入っており、CLI に設定したリージョンの Amplify アプリを走査して backend environment が 1 つも無ければ「AWS Amplify Gen 1 has entered maintenance mode and will no longer accept new customers.」で `amplify init` を中断します。Gen 1 を使ったことがないアカウントでは、選ぼうとしても初期化できません。

## Gen 1の記事からGen 2へ置き換えるコマンドとインポート

2024 年前半の記事に載っているコマンドと、Gen 2 での対応物です。対応付けは AWS の[Gen 2 移行フィーチャーマトリクス](https://docs.amplify.aws/react/start/migrate-to-gen2/feature-matrix/)に沿っています。

| 用途       | Gen 1（旧）             | Gen 2（現行）                   |
| -------- | -------------------- | --------------------------- |
| プロジェクト作成 | `amplify init`       | `npm create amplify@latest` |
| 認証の追加    | `amplify add auth`   | `amplify/auth/resource.ts`  |
| 環境の管理    | `amplify env add` ほか | Git ブランチ                    |
| 開発者ごとの検証 | `amplify mock`       | `npx ampx sandbox`          |
| 本番へ反映    | `amplify push`       | `npx ampx pipeline-deploy`  |
| 接続情報ファイル | `aws-exports.js`     | `amplify_outputs.json`      |

取り違えやすいのは 4 行目と 5 行目です。`ampx sandbox` は `amplify/` の変更を監視して開発者個人のスタックへ反映し続けるコマンドで、公式は「Cloud sandbox environments are designed for development purposes and are not intended for production workloads.」と書いています。`amplify push` の置き換え先は `pipeline-deploy` か Amplify Hosting の自動ビルドです。Gen 2 の CLI 全体は[AWS Amplify Gen 2の使い方：ampxで初期化からCI/CDまで【2026年版】](/tech/details/2842/)、Gen 1 と Gen 2 の設計の違いと料金は[AWS Amplifyとは？Gen 2のバックエンド定義と料金・採用判断を実装者目線で解説](/tech/details/15590/)で扱っています。

### Amplify JavaScript v5.0.0でのデフォルトインポート廃止

古いサンプルの `import Amplify from 'aws-amplify'` は現行版では動きませんが、これは Gen 1 と Gen 2 の違いではありません。unpkg で公開版を見ると、デフォルトエクスポートがあるのは `aws-amplify@4.3.46` までで、型定義に「@deprecated use named import」と付いています。消えたのは 5.0.0（2022 年 11 月 8 日）です。v6 の変更点は `import { signIn } from 'aws-amplify/auth'` のようなカテゴリ単位のインポートでした。

現行の 6.22.1（2026 年 9 月 28 日）では、6.22.0 で `createAmplifyContext` と `createConfigurationBuilder` がトップレベルに加わりました。`createAmplifyContext` は型定義の説明どおり「not set as the global context」で、リクエストごとに設定を分けたいサーバー側やマルチテナント向けです。サーバーを持たない SPA モードでは、これまでどおり `Amplify.configure()` を 1 回呼べば足ります。バックエンド側は `@aws-amplify/backend` 1.25.1、`@aws-amplify/backend-cli` 1.10.0 で、CLI の engines は `^18.19.0 || ^20.6.0 || >=22` です。Node.js を 22.22 以上にそろえれば React Router v8 とも衝突しません。

## React Router v8のSPAモードとAmplify Gen 2の接続設定

ここからのコードは React Router 8.4.0・aws-amplify 6.22.1・Node.js 26.5.0 でビルドを実行して確かめたものです。

### ssr:falseでのrootのビルド時描画

SPA モードは `react-router.config.ts` の 1 行で有効になります。

```
import { type Config } from "@react-router/dev/config";

export default {
  ssr: false,
} satisfies Config;
```

[React Router の SPA ガイド](https://reactrouter.com/how-to/spa)は、`ssr:false` が止めるのは runtime server rendering だけで「React Router will still server render your root route at build time to generate the index.html file」と書いています。root の初期描画で `window` に触れるとビルドが落ちます。`HydrateFallback` に `window.innerWidth` を書いて 8.4.0 でビルドすると、`ReferenceError: window is not defined` の後に次のエラーで終了コード 1 になりました。

```
Error: Prerender: Request failed for /: SPA Mode: Received a 500 status code from `entry.server.tsx` while prerendering your SPA Fallback HTML file.
```

Amplify UI の `Authenticator` のように DOM を前提にしやすい部品は、root の `HydrateFallback` ではなく、ハイドレーション後に描画される子ルートへ置いてください。もう 1 つ、正常なビルドでも `build/server/index.js` が残りました。配信するのは `build/client` だけです。

### amplify\_outputs.jsonの読み込みと.gitignoreの関係

接続情報は Gen 2 が生成する `amplify_outputs.json` を root モジュールで読み込み、`Amplify.configure()` に渡します。モジュール直下で呼んでもビルド時の描画は通りました。

```
// app/root.tsx
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
import { Amplify } from "aws-amplify";
import outputs from "../amplify_outputs.json";

Amplify.configure(outputs);

export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ja">
      <head><meta charSet="utf-8" /><Meta /><Links /></head>
      <body>{children}<ScrollRestoration /><Scripts /></body>
    </html>
  );
}

export function HydrateFallback() {
  return <p>読み込み中…</p>;
}

export default function Root() {
  return <Outlet />;
}
```

JSON を import するので `tsconfig.json` に `resolveJsonModule: true` が要ります。注意したいのは、`npm create amplify@latest`（create-amplify 1.4.1）が `.gitignore` に `amplify_outputs*` を書き込むことです。手元では `npx ampx sandbox` が生成するので動きますが、リポジトリには入りません。そのまま Amplify Hosting でフロントだけをビルドすると、次のエラーで止まります。

```
✗ Build failed
Could not resolve "../amplify_outputs.json" from "app/root.tsx"
```

接続情報をデプロイ先のバックエンドと一致させるため、後述の `amplify.yml` でフロントのビルド前に生成します。

### clientLoaderによるAmplify Dataの取得

以下の `clientLoader` の例は `app/routes/todos.tsx` に置きます。標準の構成ではファイルの追加だけではルートにならないため、`app/routes.ts` で `@react-router/dev/routes` の `route` をインポートし、既存の配列へ `route("todos", "routes/todos.tsx")` を追加してください。

SPA モードでは root 以外のルートに `loader` を書けません。試しに子ルートへ `loader` を足すと、8.4.0 は次のメッセージで終了コード 1 を返しました。

```
[react-router:route-exports] SPA Mode: 1 invalid route export(s) in `routes/todos.tsx`: `loader`. See https://reactrouter.com/how-to/spa for more information.
```

Amplify Data（AppSync）への問い合わせは `clientLoader` に置きます。クライアントの作り方は[Amplify の Connect to API ページ](https://docs.amplify.aws/react/build-a-backend/data/connect-to-API/)と同じです。

```
// app/routes/todos.tsx
import { generateClient } from "aws-amplify/data";
import type { Schema } from "../../amplify/data/resource";
import type { Route } from "./+types/todos";

const client = generateClient<Schema>();

export async function clientLoader() {
  const { data, errors } = await client.models.Todo.list();
  if (errors) throw new Response("Todo の取得に失敗しました", { status: 500 });
  return { todos: data };
}

export default function Todos({ loaderData }: Route.ComponentProps) {
  return (
    <ul>
      {loaderData.todos.map((t) => <li key={t.id}>{t.content}</li>)}
    </ul>
  );
}
```

root の `loader` だけは認められていて、ビルド時に 1 回実行されます（`HydrateFallback` の `loaderData` で受け取る）。Remix v2 はさらに厳しく、[v2 の SPA Mode ガイド](https://v2.remix.run/docs/guides/spa-mode)は「You cannot use server APIs such as `headers`, `loader`, and `action` \-- the build will throw an error if you export them」と root を含めて禁止しています。両系列の解説を混ぜて読むとここで食い違います。`clientLoader` と `clientAction` の使い分けは[React Routerのaction・loaderの使い方｜clientAction/clientLoaderの違いとv8対応](/tech/details/4436/)を参照してください。

### 既定の認可モードと公開前の切り替え

サーバーを通さない構成では、AppSync の認可設定がそのままセキュリティ境界です。create-amplify 1.4.1 が生成する `amplify/data/resource.ts` は `allow.guest()` と `defaultAuthorizationMode: 'identityPool'` で、未認証の Cognito ID プールロールに全操作を許した状態から始まります。公式の Set up data ページの例は `allow.publicApiKey()`（`expiresInDays: 30`）で、こちらを写すと API キーがブラウザに配られたまま公開されます。非公開データをユーザープール認証で扱う場合は、個人別データなら `allow.owner()`、全ログインユーザーで共有するデータなら `allow.authenticated()` へ切り替え、`defaultAuthorizationMode` を `'userPool'` にしてください。ログイン画面の作り込みは[AWS Cognito Hosted UI（マネージドログイン）のカスタマイズ・日本語化と実装手順](/tech/details/3441/)が参考になります。

## Amplify Hostingのamplify.ymlとリライト設定

### amplify.yml：backendでpipeline-deploy、成果物はbuild/client

フロントとバックエンドを 1 つのリポジトリに置く構成では、ビルド設定を次のように書きます。backend フェーズの 2 行は [Amplify のマルチリポジトリ解説](https://docs.amplify.aws/react/deploy-and-host/amplify-hosting/mono-and-multi-repos/)に載っている形そのままで、`$AWS_BRANCH` と `$AWS_APP_ID` は Amplify Hosting がビルド環境に入れる変数です。

```
version: 1
backend:
  phases:
    build:
      commands:
        - npm ci --cache .npm --prefer-offline
        - npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
frontend:
  phases:
    build:
      commands:
        - npm run build
  artifacts:
    baseDirectory: build/client
    files:
      - '**/*'
  cache:
    paths:
      - .npm/**/*
      - node_modules/**/*
```

この順番に意味があります。`@aws-amplify/backend-cli` 1.10.0 の `pipeline-deploy` は、バックエンドをデプロイした後に `amplify_outputs.json` を書き出す実装で、出力先は `--outputs-out-dir` を省くと「current process working directory」、つまりリポジトリ直下です。frontend の `npm run build` はその後に走るので、前の節の import が解決します。`--branch` と `--app-id` はどちらも必須で、CI 環境と判定されないと「It looks like this command is being run outside of a CI/CD workflow.」で止まります。

`baseDirectory` を `build` にすると、SPA モードでも残る `build/server/index.js` まで公開領域に上がります。必ず `build/client` を指定してください。バックエンドを別リポジトリにする場合は、backend フェーズを `npx ampx generate outputs --branch main --app-id <バックエンドのアプリID>` に替えて取得だけにします。

### 拡張子を除外したSPAフォールバックの200リライト

直接開いた URL を `index.html` へ返すリライトが要ります。ここで `/<*>` の catch-all を単独で置くと、`.js` や `.css` まで `index.html` に書き換わってアプリが起動しません。[AWS の SPA 向けの例](https://docs.aws.amazon.com/amplify/latest/userguide/redirect-rewrite-examples.html)は拡張子を除外した正規表現です。

```
送信元: </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json|webp)$)([^.]+$)/>
送信先: /index.html
種類  : 200
```

Amplify のリダイレクトは[「Redirects are applied from the top of the list down」](https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html)と上から順に評価され、実ファイルを優先するという規定はありません。トップからの画面遷移は動くのに、同じ URL を直接開くと 404 になるなら、まずこの規則の有無と順番を確かめてください。

### prerender併用時のSPAフォールバックの配信先

一部のページだけ HTML を事前生成したいときは、`ssr: false` のまま `prerender` を足せます。[React Router の pre-rendering ガイド](https://reactrouter.com/how-to/pre-rendering)のとおり、事前生成するパスのルートは `loader` を持てます。ただし `/` を含めるとフォールバックのファイル名が変わります。`prerender: ["/"]` で 8.4.0 をビルドした結果がこれです。

```
Prerender (html): / -> build/client/index.html
Prerender (html): SPA Fallback -> build/client/__spa-fallback.html
```

この場合、上の正規表現の送信先は `/__spa-fallback.html` に替えます。`/` も正規表現に一致するので、その上に「`/` → `/index.html`（200）」を置いて事前生成した HTML を守ります。他の事前生成パスも同じで、正規表現より上に個別の規則を足し、デプロイ後に curl で本文入りの HTML が返るかを確かめてください。

loader を持つパスを事前生成すると、クライアント遷移用のデータも `.data` ファイルとして出力されます。`/about` を追加してビルドすると `build/client/about.data` が生成され、AWS の正規表現はこの `/about.data` にも一致しました（Node.js で照合）。そのままでは画面遷移時のデータ要求まで HTML に書き換わるので、prerender を使うときは除外リストの末尾に `data` を足します。

```
送信元: </^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json|webp|data)$)([^.]+$)/>
送信先: /__spa-fallback.html
種類  : 200
```

## SSRが必要になったときのdeploy-manifest自作

[Amplify Hosting の SSR 対応](https://docs.aws.amazon.com/amplify/latest/userguide/server-side-rendering-amplify.html)でアダプタなしに動くのは Next.js だけで、Nuxt は preset アダプタ、Astro と SvelteKit はコミュニティアダプタが前提です。Remix と React Router はこの一覧にありません。SSR で動かすなら `.amplify-hosting/static`、`.amplify-hosting/compute/default`、`deploy-manifest.json` を自前で組み、compute 側でポート 3000 の Node.js サーバーを起動します。

ここで古い解説をそのまま写すと manifest で落ちます。日本語で読める Remix の手順には `"runtime": "nodejs18.x"` の例が残っていますが、[デプロイ仕様](https://docs.aws.amazon.com/amplify/latest/userguide/ssr-deployment-specification.html)の現在の有効値は `nodejs20.x`・`nodejs22.x`・`nodejs24.x` の 3 つだけです。しかも React Router v8 は Node.js 22.22 以上、Remix 3 は 24.3 以上を要求するので、実際に選べるのは v8 なら `nodejs22.x` か `nodejs24.x`、Remix 3 なら `nodejs24.x` だけになります。

SPA モードならこの作業がすべて不要で、compute の料金もかかりません。静的配信なら S3＋CloudFront という選択肢もあり、比較は[AWS Amplify Hostingとは？料金・特徴とS3+CloudFront/App Runnerとの違い](/tech/details/7252/)にまとめています。既存の AWS 環境との統合や移行を含めて設計を任せたい場合は、[AWSのインフラ構築支援](/service/system/aws/)で相談を受け付けています。

## この構成を採用すべきでない3つの条件

次のどれかに当てはまるなら、Remix SPA モード＋Amplify Gen 2 は選ばないでください。

**検索流入が柱になる画面がある。**SPA モードの `index.html` は root しか描画せず、商品詳細や記事本文はクローラが最初に受け取る HTML に入りません。対象ページが固定なら `prerender`、動的なら SSR を選びます。後者は上の deploy-manifest の自作が前提になるので、Next.js を Amplify に載せる方が手間は少なくなります。

**新規プロジェクトで Remix v2 を選ぶ。**v2 系の公開版は 2.17.5（2026 年 6 月 1 日）から更新がなく、`remix` の名前は 3.0.0 に移りました。新規なら React Router v8（Node.js 22.22 以上・React 19.2.7 以上）で組みます。v2 に留まる理由になるのは、既存の v2 アプリを保守している場合だけです。

**既存の業務APIを中心に据え、Amplify Dataを追加する必要がない。**Amplify Data は AppSync のスキーマを中心に、クライアントから直接呼ぶ設計です。Gen 2 は既存の MySQL・PostgreSQL に接続できるため、RDB の利用だけでは不採用の理由になりません。既存の業務APIで認可やトランザクションを完結でき、AppSyncを追加する利点がない場合は、Amplify Dataを使わず既存APIへ接続する構成を選びます。この場合も Amplify Hosting の静的配信はそのまま使えるので、外すのは Gen 2 のバックエンドだけです。

## よくある質問

### Remix SPAモードでAmplify Gen 2のデータAPIは使えますか？

使えます。root 以外に `loader` を書けないため、取得は `clientLoader`、更新は `clientAction` に置き、`generateClient<Schema>()` で作ったクライアントから呼びます。Remix v2 では root も含めて `loader` を export できません。生成直後のスキーマは `allow.guest()` で未認証アクセスを許します。非公開の個人別データにはユーザープール認証と `allow.owner()` を設定し、公開データには公開範囲に応じて操作を制限してください。

### Amplify HostingのビルドでCould not resolve amplify\_outputs.jsonと出るのはなぜですか？

`npm create amplify@latest` が `.gitignore` に `amplify_outputs*` を入れるため、リポジトリにファイルが無いからです。`amplify.yml` の backend フェーズに `npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID` を書けば、デプロイ後にリポジトリ直下へ生成され、続く frontend のビルドで読み込めます。

### Amplify HostingでSPAのURLを直接開くと404になるのはなぜですか？

主な原因は、SPA フォールバックのリライト規則の未設定や、規則の順序・送信先の誤りです。「書き換えとリダイレクト」に、拡張子を除外した正規表現を送信元、`/index.html` を送信先、種類 200 で追加します。`prerender` で `/` を事前生成している場合の送信先は `/__spa-fallback.html` です。単純な catch-all では JavaScript や CSS まで書き換わり、今度はアプリが起動しなくなります。

### Cognitoの認証UIはSPAモードでも動きますか？

動きますが、置き場所に条件があります。root はビルド時に Node.js 上で描画されるため、root の `HydrateFallback` で `window` に触れるとビルドが失敗します。`@aws-amplify/ui-react`（6.15.7）の `Authenticator` は、ハイドレーション後に描画される子ルートへ置いてください。

### これから作るならRemix v2・React Router v8・Remix 3のどれですか？

React Router v8 です。Remix v2 の公開版は 2.17.5 のままで、`npm i remix` で入る 3.0.0 は React を使わない別系列で SPA モードもありません。React と Amplify UI を使う前提なら、v8 の `ssr: false` で組むのが 2026 年 10 月時点でいちばん素直な構成です。

## 関連記事

- [Remix SPAモードとは？ssr:falseの設定と制約、React Router移行の判断](/tech/details/3840/)
- [React Routerのaction・loaderの使い方｜clientAction/clientLoaderの違いとv8対応](/tech/details/4436/)
- [AWS Amplify Gen 2の使い方：ampxで初期化からCI/CDまで【2026年版】](/tech/details/2842/)
- [AWS Amplifyとは？Gen 2のバックエンド定義と料金・採用判断を実装者目線で解説](/tech/details/15590/)
- [AWS Amplify Hostingとは？料金・特徴とS3+CloudFront/App Runnerとの違い](/tech/details/7252/)

---

出典: [Remix SPAモード（React Router v8）とAmplify Gen 2の構成手順｜amplify.ymlとリライト設定](<https://www.issoh.co.jp/tech/details/2281/>)（株式会社一創）
