Lately, I’ve been getting more and more questions about why I choose Remix over Next.js in many cases. With this article, I want to show in what situation and for what reasons I prefer Remix over Next.js.
Case study
Suppose you are building an Enterprise Search application 😛. The data received by the user is dynamic and depends on that user’s permissions and searches. This article shows why I prefer Remix over Next.js in such a case.
User Experience and Performance
With a dynamic application, it is essential to provide a fast and smooth user experience. As a front-end developer, I see it as my job to ensure that users experience minimal load times, and if possible with as little client-side JavaScript 😬. Remix is perfect for this, as the framework by itself allows most data and mutation logic to be handled on the server side, leading to better performance.
Remix: Server-side Data Mutations with Actions
On the Web, you could actually say that any kind of data mutations can go through a form (yes, even a simple button) Within Remix, all data mutations (such as searches) can be handled through server-side actions. This avoids having to write unnecessary client-side JavaScript to handle data changes. Through actions and useActionData hook we can capture the response of an action to display the results. To provide a fancy experience, we can use the useNavigation hook to track the status of the query (loading states, etc.)
This approach allows you to process the entire search logic server-side, without the need for additional client-side fetches.
By the way, did I mention anything about nested routes? Within Remix, you can apply this same principle for child routes. Each child route can have its own loader and action, which work independently of the parent route. This means you can dynamically load data and handle mutations on each nested route, without needing a lot of extra client-side logic.
How Next.js Handles Data Mutations
In Next.js, you can use getServerSideProps to load data server-side, but to mutate data, you often need an additional API route. This can increase the complexity of your application because you have to manage both server-side and client-side logic. Here is an example of how to create an API route in Next.js for processing queries.
This route accepts a POST request, processes the query and returns the results. We could then send a client-side fetch request to this API.
This requires quite a bit of manual logic for managing load states and error handling. And of course, in this situation you can choose a solution like react-query to simplify your state management a bit.
The point I want to make is that in this situation, Remix doesn’t even need react-query.
It can get quite complex if you have a lot of endpoints, which is one reason why Remix can be more attractive with its built-in support for forms and server-side data handling.
While Next.js is powerful and is often the best choice for applications with Static Site Generation or Client Side Rendering, for example, Remix excels in situations where dynamic content and server-side rendering are key. For complex applications such as our Enterprise Search application, Remix provides an efficient approach that better manages server-side logic and minimizes client-side JavaScript.
In short, Remix makes building dynamic applications easier, with less client-side code, more focus on performance and progressive enhancements for key functionality of your application.
I look forward to hearing from you! Do you have any suggestions or experiences you’d like to share? Let me know!