The React ecosystem is a bustling landscape, brimming with frameworks promising to revolutionize web development. Today, we’ll be diving into two popular contenders: Next.js and Remix.
Next.js is one of the most popular React frameworks used for server-side rendering. It’s been there for a significant time, and it provides an exceptional developer experience with all the features developers need.
Remix, a newer entrant into the scene, was created by the founders of React Router. It promotes a full-stack development approach and brings several innovative features. With the open-source introduction of Remix in 2022, developers have started to wonder which the better framework for their application is.
Both boast impressive features and passionate communities, but which one should grace our next project?
Let’s break down their strengths and weaknesses to help us pick the champion.
1. Routing
Next.js
Next.js has two different routers: the App Router and the Pages Router. The App Router is a newer router that allows us to use React’s latest features, such as Server Components and Streaming. The Pages Router is the original Next.js router, which allowed us to build server-rendered React applications and continues to be supported for older Next.js applications.
For the app route, Next.js 13 uses directory-based routing where
any file under /app
called page.tsx gets built as a route.
The folders in the app
directory can contain
layout.tsx
for layouts, page.tsx
to make that route publicly accessible,
loading.tsx
to define the loading state and error.tsx
for error handling.
To create a nested route, we can nest folders inside each other.
Routing
Source: Next.js docs
Folder structure
Source: Next.js docs
Remix
Remix v2, uses a flat-file-based routing system.
In our /app/routes
folder, we can create new routes by adding new components.
Creating a nested route is done using a period delimiter(.
) in the file name.
For example, if we want to create a /concerts/trending
route in our Remix app,
we would add a new file called concerts.trending.tsx
.
Source: Remix docs
Point of View
Now, if we compare the routing mechanisms of both these frameworks, both have chosen pretty much the same direction for file-system-based routing, and it feels like the right way to go.
Remix seems to be more intuitive, we can tell what route the file/layout represents just by looking at it. But as per Next.js, it also makes sense to put related routing files in one folder which helps to define our loading/error states for each of our route segments.
2. Data Fetching
Next.js
Next.js provides several data fetching methods:
getServerSideProps
: Fetches data on the server during each request. This is used for server-side rendering (SSR), where the data is fetched when the page is requested by the client.getStaticProps
: Fetches data at build time, generating static HTML pages with pre-rendered content.getInitialProps
: Runs on both server and client, enabling data fetching for initial rendering and client-side hydration. It is a legacy API.fetch
: Next.js extends the nativefetch
Web API to allow us to configure the caching and revalidating behavior for each fetch request on the server.fetch
with async/await can be used in Server Components, in Route Handlers, and in Server Actions.
Remix
In Remix, data is fetched in the loaders. Each route can define a loader function
that provides relevant data to the route when rendering.
useLoaderData
provides the loader’s data to the component.
Loaders are only run on the server.
Point of View
Next.js seems to be ideal for applications with a mix of static and dynamic content, where flexibility and customization are prioritized. Remix’s data fetching approach allows for finer control over data loading and dependencies.
3. Data mutations
When dealing with mutations, we often handle them by sending API requests to a backend server and then updating the local state to reflect the changes.
Both frameworks aim to revolutionize mutation handling by integrating it directly into their core features.
Next.js
Before Next.js 13.4, the only way to create and take action on the server was by creating API routes and updating the state.
Next.js 13.4 introduced server actions to handle data mutations to simplify the developer experience and improve the user experience.
// Using API route
//Using server actions
Example taken from Next.js 14 forms and mutations
Remix
Remix automatically keeps the UI in sync with the persistent server state. It happens in three steps:
- Route loaders provide data to the UI
- Forms post data to route actions that update persistent state
- Loader data on the page is automatically revalidated
Remix encourages to keep every part of the application where the user takes an action to be an HTML form. Whenever the user triggers a form submission, it calls the action. Once the action is executed, Remix refetches all the loaders for that route via the browser fetch request and refreshes the UI, ensuring that the UI always stays in sync with the database. This is called the “full-stack data flow” of Remix.
The example is taken from Remix route action doc.
Point of View
- Next.js server actions are tied with the React ecosystem and APIS from React. Whereas Remix is implemented on what the web platform does and is closely associated with how the web works.
- Next.js actions are component-centric. Whereas Remix actions are route-centric so not as composable as components.
- In Next.js we need to manually tell to revalidate the path whereas Remix does automatic revalidations
These are tradeoffs of Next.Js and Remix, we can decide which ones we can live with and which we need and decide accordingly.
4. Error handling
Both Next.js and Remix offer mechanisms for handling errors gracefully in our web applications.
Next.js
There is a separate error.js
file in each route segment for rendering the error state for that route.
The error.js file convention allows us to gracefully handle unexpected runtime errors in nested routes
by automatically wrapping a route segment and its nested children in a React Error Boundary.
It handles both unexpected errors that might occur on the server or in
the browser and expected errors like 404.
Remix
To render the error state for a route segment, we can export ErrorBoundary
.
It handles both unexpected errors that might occur on the server
or in the browser and expected errors like 404.
5. Community Support
Next.js
Next.js is a well-established framework with 118k⭐ GitHub stars (at the time of writing). It has a large community and ecosystem, a significant advantage when looking for solutions to problems, plugins, or integrations.
Remix
Remix has around 26.6k⭐ GitHub stars (at the time of writing) and a growing community.
Point of View
Prefer Remix if the application is not complex and does not need much help from the community. If an application requires a framework with a wider range of features and a large community of users, Next.js is a good choice.
6. Learning Curve
Next.js
Relatively difficult to learn. It provides lots of choices and low-level control might overkill if developers don’t use them correctly.
Remix
Relatively simple. It provides only one way to do things and abstract lots of things out.
7. Deployment
Next.js
Deploying Next.js can be challenging outside of Vercel, which is an excellent platform but may not be ideal if our infrastructure is on AWS. Hosting Next.js in our AWS account offers easier integration with our backend and is often more cost-effective than Vercel. While Next.js doesn’t have native support for self-hosting with serverless, we can run it as a Node application. However, this approach may not provide the same benefits as using Vercel.
Fortunately, there’s a new open-source Next.js serverless adapter - OpenNext. This adapter takes the Next.js build output and converts it into a package that can be deployed to any functions as a service (FaaS) platform, making deployment more flexible.
Kent Dodds expresses his concern about the deployment in his blog.
Remix
Remix was designed for deployment on any platform that supports JavaScript execution. This is largely due to its focus on standards.
8. Pricing
Next.js
Vercel’s pricing seem to be a big problem for a lot of folks. It can be important point to be considered.
We we're quoted $40k for ▲ (after rejecting 150k for enterprise tier) for just static asset applications we wanted to move.
— Zackery Griesinger (@zackerydev) October 26, 2023
Our current Cloudfront bill per month: 12$
However Lee Rob, the VP of Product at Vercel mentioned in his post that they are working on improving the pricing
Remix
As Remix can be deployed on any platform that supports JavaScript execution, we are free to choose the platform as per our choice.
9. Partnership with big brands
Next.js
Next.js is maintained by Vercel. The React team is closely working with the Next.js team to ship new features such as React Server Components.
Remix
Remix has joined forces with Shopify in 2022! Under Shopify’s stewardship, Remix receives long-term backing and support from an established leader in commerce.
10. Companies
Next.js
The detailed list can be seen here.
Remix
- NASA
- Docker - Docker Scout is a unified container security solution designed to help developers quickly identify and fix vulnerabilities in all repositories,
- Shopify
- react-admin - To serve a private npm registry and Enterprise user dashboard.
The detailed list can be seen here.
So, who takes the crown?
And the winner is…
It’s a tie! Both Next.js and Remix excel in different areas.
However, the “best” framework hinges on the project’s unique needs:
For: Large-scale projects, feature-rich frameworks, and quick wins with extensive support - Next.js might be the champion.
For: Performance-critical projects, smooth user experience, solving less complex problems, and a willingness to explore a modern approach - Remix could be the champion.
Remember:
Both frameworks boast active communities and growing resource pools. Hands-on experimentation is key. Build small projects with each to discover the personal fit. The team’s skills and preferences matter. Choose the framework that aligns with the team’s development style.
Happy coding!