deleted
このWebサイト、『記事もコメントも自動で翻訳される多言語コミュニティEvame』のメタフレームワークをRemixからNext.jsに移行し、インフラもRenderからVercelへ移行しました。
This website, 'Evame,' a multilingual community with automatic article and comment translation, migrated its meta-framework from Remix to Next.js, and its infrastructure from Render to Vercel.
2週間ほどかけての大掛かりな移行でしたが、結果には満足していて、「小〜中規模なサイトならRemix / React Router、大規模なサイトならNext.jsを選ぶ価値が大いにある」という結論に至りました。
It was a large-scale migration taking about two weeks, but I'm satisfied with the results. I've concluded that Remix/React Router is a great choice for small to medium-sized sites, while Next.js is highly valuable for larger ones.
この記事では、RemixからNext.jsへの移行についてや、RemixとNext.jsの個人的な比較について書きます。どっちを使うか悩んでいる人や、移行を考えている人はぜひ読んでください!
This article details the migration from Remix to Next.js and offers a personal comparison of the two. If you're struggling to choose or considering a migration, please read on!
サイト方針の変更と規模の拡大
Website Policy Changes and Expansion of Scale
当初Evameは、青空文庫やプロジェクト・グーテンベルク、過去の仏典と言ったpubllic domainのテキストに対訳を付与したくて始めました。しかし開発を進めるうちに、public domainのテキストだけではなくユーザが投稿した記事にも対訳を付与できるようにしたいと考えるようになりました。そもそもEvameを作り始めた目的は知識と物語の循環であり、そのためにはユーザーが記事を投稿できるシステムが必要不可欠だと考えたからです。この方針の変更によってサイトの規模が拡大し、必要な機能が増え、大きなエコシステムを持つNext.jsに惹かれるようになりました。
Initially, Evame started with the goal of providing translations for public domain texts like those from Aozora Bunko, Project Gutenberg, and old Buddhist scriptures. However, as development progressed, we wanted to extend translation capabilities to user-submitted articles as well. The fundamental purpose of Evame is the circulation of knowledge and stories; a system allowing user contributions is essential to this goal. This policy change led to increased site scale, new functional requirements, and a growing attraction to the robust ecosystem of Next.js.
Remixの今後の不明瞭さ
Uncertainties Regarding the Future of Remix
2024/11/22、Remix v2はReact Router v7とマージされました。https://remix.run/blog/react-router-v7
On 2024/11/22, Remix v2 merged with React Router v7. https://remix.run/blog/react-router-v7
Remixは消え、React Routerとして続いていくのかと思っていましたが、上記ブログの著者でもあるCo-FounderがTwitterで、次はRemix v3になるという発言をしています。
I thought Remix would disappear and continue as React Router, but the co-founder, also the author of the above blog post, stated on Twitter that the next version would be Remix v3.
名前の変更はエコシステム全体に変化を余儀なくさせる大きなものです。実際、別のプロジェクトでRemix v2からReact Router v7へアップデートしたのですが、Remix関連の各種ライブラリが使えなくなり、多くの対応が必要で結構な工数がかかりました。再度名前の変更で同様の対応を迫られる可能性もあり、そうすると今回アップデートしてもまた使えなくなるライブラリが多く出るかも、といった不安がありました。
Renaming a framework significantly impacts the entire ecosystem. In another project, updating from Remix v2 to React Router v7 rendered many Remix-related libraries unusable, requiring extensive adjustments and significant effort. The possibility of facing similar challenges with another renaming, potentially breaking many libraries again, was a major concern.
React と Next.js の緊密化
Tightening Integration Between React and Next.js
https://nextjs.org/blog/next-12
https://nextjs.org/blog/next-12
ReactとNext.jsは、上記の記事にもあるようにどんどん連携を深めており、Next.jsは他のフレームワークよりも先行して多くの技術を使用しています。
As noted in the above article, React and Next.js are increasingly intertwined, with Next.js pioneering many technologies ahead of other frameworks.
RSCがNext.jsでリリースされたのは2023年でもう2年近く経っているのに、まだRSCを使えるフレームワークがほとんどないことがその証明です。
The fact that few frameworks still support RSC, despite its release in Next.js in 2023 (nearly two years ago), is evidence of this.
今後も優先的に新機能を実装できるだろう点は大きなアドバンテージだと感じました。
The ability to prioritize new feature implementation is a significant advantage.
React 19がフルに活用できる
Full Utilization of React 19
Remix / React Router v7 だと、route modulesの loader / action でデータを扱うため、コンポーネントとデータ部分が分離しがちでした。
Next.js(App Router)ではRSC (React Server Components) や Server Actions 、useActionState等を活用することで、コンポーネントとデータの距離が縮まり、開発生産性が向上しました。また、コロケーションに基づいたディレクトリ構成がRemixより行いやすくなった点も開発生産性の向上に繋がりました。
With Remix/React Router v7, data handling within route modules' loaders/actions often resulted in a separation between components and data. Next.js (App Router), using RSC (React Server Components), Server Actions, useActionState, etc., minimizes this distance, improving development productivity. The directory structure based on colocation is also easier to implement than in Remix, further boosting productivity.
豊富なエコシステム
Rich Ecosystem
Next.jsの場合、Sentry、Supabase、Stripe など多くのサービスの公式例があり、周辺ライブラリも充実しています。next/font や next/image も素晴らしく、これによってLight HouseのPerformanceが100点になり、Best Practicesも100点になりました。
Next.js boasts official examples for many services like Sentry, Supabase, and Stripe, and abundant supporting libraries. next/font and next/image are excellent, resulting in a perfect Lighthouse Performance and Best Practices score of 100.

移行前は以下の点数だったので、エコシステムの力を大いに感じています。(Accessibility頑張ります。)
Before the migration, the scores were lower, highlighting the significant impact of the ecosystem. (We'll work on Accessibility!)

AIフレンドリー
AI-Friendly
ClaudeやGPTに、Remixで書いてと指示を出してもNext.jsのコードを吐いてくることがよくありました。ユーザが多い分、Next.jsの場合最初から使えるコードを出してくれる割合が増えたと感じます。これもAI時代の新たなエコシステムと呼べるかもしれません。
When asking Claude or GPT to write code in Remix, it often generated Next.js code. The larger user base seems to increase the likelihood of Next.js producing usable code from the outset. This could be considered a new ecosystem for the AI era.
ビルドが遅い
Slow Build Times
Remix は HMR が速く、ローカル開発が非常に快適でした。Next.js はファイルによってはビルドに数秒かかり、時にはリロード必須になるなど、開発体験としてはストレスがあります。
Remix's HMR is fast, providing a very comfortable local development experience. Next.js, however, can take several seconds to build certain files, sometimes requiring a manual reload, resulting in a frustrating development experience.
メンタルモデルの複雑さ
Complex Mental Model
Remixのメンタルモデルは、loader→component→actionというシンプルでわかりやすい流れでした。
Remix's mental model is simple and clear: loader → component → action.
Next.jsの場合、RSC/Server Actions/revalidatePath/revalidateTag/next/dynamic/Request Memoizationなど様々な概念が登場します。最適化されたことでLighthouseのスコアは上がりましたが、体感ではRemixの時と速度に差はありません。ユーザとしては体感速ければどうでもいいので、勝手に速くなるようにしてほしいという感想です。
Next.js introduces various concepts: RSC/Server Actions/revalidatePath/revalidateTag/next/dynamic/Request Memoization. While optimization improved Lighthouse scores, the perceived speed wasn't noticeably different from Remix. As a user, I just want it to be fast; I don't care how it's achieved.
黒魔術
Dark Magic
Remixの吐くhtmlは非常にシンプルでした。書いたものがそのまま出力されているという感じで、把握しやすかったです。
Remix generates very clean HTML; what you write is what you get, making it easy to understand.
Next.js はフレームワーク独自のロジックでclassNameやcanvasタグが差し込まれていたり、デバッグが複雑です。また、Edge Runtimeと絡んで、ローカルでは動くのに本番だと動かない問題にも遭遇しがちです。
Next.js inserts framework-specific logic (e.g., className, canvas tags), complicating debugging. Issues where code runs locally but fails in production, often involving Edge Runtime, are common.
最初にブランチを切ってcreate next し、ライブラリの移行から始めました。具体的には以下のライブラリを移行する必要がありました。
I started by creating a new branch with `create next` and began migrating libraries. This included the following:
remix-auth → auth.js
remix-auth → auth.js
react-i18next → next-intl
react-i18next → next-intl
remix-auth → auth.jsの変更には、DBスキーマの対応とORMとして使っているPrismaのEdge Runtime対応が必要で、移行全体の中でもここが一番大変でした。
The change to remix-auth → auth.js required adjustments to the DB schema and Prisma (our ORM) to support Edge Runtime. This was the most challenging part of the entire migration.
DBスキーマはauth.js側に合わせたスキーマを用意し、既存データをマイグレーションし、カスタマイズを減らすことでアップデート時のリスクを抑えました。
For the DB schema, I prepared a schema matching auth.js, migrated existing data, and minimized customizations to reduce upgrade risks.
Edge Runtimeは、Prisma Accelerate はまだ事例が少なく、ローカルと本番の差異が大きそうで懸念があり、Drizzle への移行は自由度が高い一方で工数が大きいので、結果、Neon + Prisma を選択して最小限の工数に留めました。
For Edge Runtime, Prisma Accelerate lacked sufficient examples, and the potential for significant differences between local and production environments was concerning. While migrating to Drizzle offered high flexibility, it would have been more time-consuming. As a result, I opted for Neon + Prisma, keeping the effort to a minimum.
次に、既存の Remix のルーティングや loader / action 部分を、Next.js App Router での RSC / Server Actions に置き換えました。
ここではAIが非常に役に立ちました。と言ってもuseActionStateやServer ActionはまだAIには書けないので自力で頑張る必要があります。
Next, I replaced existing Remix routing and loader/action components with Next.js App Router RSC/Server Actions. AI was extremely helpful here. However, useActionState and Server Actions still require manual coding.
Server Actions に共通ロジックを持たせない工夫
Avoiding Shared Logic in Server Actions
すべての Server Actions が外部公開されるため、認証コードをいちいち書く必要があります。できるだけ認証ロジックをまとめた関数や、Middleware で対応できないか検討しましょう。
Since all Server Actions are publicly accessible, authentication code is needed for each. Consider using functions or middleware to consolidate authentication logic where possible.
RSC コンポーネントのテスト
Testing RSC Components
RSC は 現状テスト手法が確立されていないので、ビジネスロジックや認証ロジックを分け、Unit テスト可能にするのがおすすめです。
Testing methodologies for RSC are still under development. Separating business and authentication logic makes unit testing easier.
useActionState の型付け
useActionState Typing
useActionStateの返り値に型情報を付与する仕組みはまだ確立されていません。自前で定義するのが現状ベターです。個人的には以下のようにしています。(about_hiroppyさんのtweetを参考にしています。)
A mechanism for adding type information to the return value of useActionState isn't fully established. Defining types manually is currently the better approach. I use the following method (inspired by @about_hiroppy's tweet).
export type ActionResponse<T = void, U = Record<string, unknown>> = {
success: boolean;
message?: string;
data?: T;
zodErrors?: typeToFlattenedError<U>["fieldErrors"];
};form の型検証
Form Validation
Server Action 内でバリデーションするといいです。個人的にはzodで以下のようにしています。
It's best to perform validation within Server Actions. I personally use zod as follows:
const editPageContentSchema = z.object({
slug: z.string().min(1),
title: z.string().min(1).max(100),
pageContent: z.string().min(1),
});
const parsedFormData = editPageContentSchema.safeParse({
slug: formData.get("slug"),
title: formData.
小〜中規模のアプリ
Small to Medium-Sized Apps
そこまで最新の React 機能を活用しなくても良ければ、Remix / React Router はシンプルで高速な開発体験を得やすい。メンタルモデルも明快。
If you don't need to utilize the latest React features extensively, Remix/React Router offers a simple and fast development experience. The mental model is also straightforward.
toBやSPAなら個人的にはRemix / React Router。
For B2B or SPAs, I personally recommend Remix/React Router.
中〜大規模 or エコシステムを活かしたい場合
Medium to Large-Scale or Those Wishing to Leverage the Ecosystem
Next.jsを選べばサービス・ライブラリとの連携がしやすく、将来的な React のアップデートにも先行して対応できる。
Next.js facilitates integration with services and libraries and provides early access to future React updates.
toCやSSRをしたいならNext.js。
For B2C or SSR, choose Next.js.
個人的には「リリースして伸びてきたら Next.js に移行」というアプローチも十分アリだと思います。Remix/React Routerならcloudflareを使えばコストもかなり抑えられます。ただし、移行時はやはり工数も掛かるので、将来的な拡張を見据えている場合は最初から Next.js を使う選択肢も強いです。
I believe that migrating to Next.js after initial release and growth is a perfectly viable approach. Remix/React Router with Cloudflare keeps costs down. However, migrations are time-consuming, so choosing Next.js from the start is a strong option if you anticipate future expansion.
フレームワーク、DB、インフラの移行と大掛かりな変更だったのですが、重要な部分にテストコードを書いていたことや、DB周りのコードをCQRSで分離していたことで、認証周り以外は比較的スムーズでした。改めて、コードの品質やアーキテクチャに投資することが大事だと実感しています。
The migration of the framework, database, and infrastructure was extensive. However, having test code for critical parts and separating DB code using CQRS resulted in a relatively smooth process, except for authentication. I've reaffirmed the importance of investing in code quality and architecture.
このサイト「Evame」は、書いた記事やコメントをAIが自動翻訳してくれる多言語コミュニティです。僕もこの移行記を日本語で書き、英語圏にシェアできるようになりました。
Evame is a multilingual community where AI automatically translates articles and comments. This migration allowed me to write this migration report in Japanese and share it with an English-speaking audience.
もし興味があれば、ぜひ好きな言語で記事を書いて、世界中に発信してみてください!
If you're interested, please write an article in your preferred language and share it with the world!
以上が、Remix / React Router v7 から Next.js へ移行した感想と比較、そして移行手順です。何か参考になる部分があれば嬉しいです!
These are my thoughts, comparisons, and migration steps from Remix/React Router v7 to Next.js. I hope this is helpful!
I don't have any further plans to work on RR v7. I'm personally done with that project. Remix v3 is just something I've been calling it internally. Since we haven't released a v3 yet, it would make sense to publish the next version of Remix as v3.