Next.js and Remix — a Brief Comparison

See how these two stack up against each other.

Kacper Łukawski




Kacper Łukawski
Kacper Łukawski
Dec 8, 2021
min read

What’s a Rich Text element?

The rich text element allows you to create and format headings, paragraphs, blockquotes, images, and video all in one place instead of having to add and format them individually. Just double-click and easily create content.
  • test
  • test
  • test

Static and dynamic content editing

  1. xxx
  2. yyy
A rich text element can be used with static or dynamic content. For static content, just drop it into any page and begin editing. For dynamic content, add a rich text field to any collection and then connect a rich text element to that field in the settings panel. Voila!

How to customize formatting for each rich text

Headings, paragraphs, blockquotes, figures, images, and figure captions can all be styled after a class is added to the rich text element using the "When inside of" nested selector system.




Next.js is a well-known React framework. It’s been around for a few years now. It allows you to create feature-rich React applications without compromising performance and SEO. Remix was created to solve the same issues, but with a different approach. I’ve had a chance to work with it recently, here are my thoughts about these two contenders.


Both frameworks support a file-system-based routing:


Next.js uses its own implementation, while Remix utilises React Router underneath. Thanks to this, Remix has an advantage in something that has been a pain point for Next.js for a long time — nested routing with nested layouts.

Nested routes structure

Imagine having a route like [categorySlug]/[subcategorySlug]. Next.js doesn’t provide a built-in solution to share the layout. You would typically reuse the same component for each part of the route.

Parent route:

Nested route:

In Remix, you can have each route render its part of the layout. And thanks to nesting it will all render on the same page.

Another difference is in the declaration of dynamic routes. In Next.js you use [] to indicate a route with parameter. In Remix, you use $ sign as a prefix in route name.

SSR is the way

Next.js comes with three different page rendering strategies.

Remix comes with a different approach, betting on SSR as the solution. At this point you may think: “Why limit yourself to SSR only? SSG is amazing and ISR is like SSG with superpowers!”.

With Remix, it’s not required to statically generate your pages. You can use other solutions that existed for many years: CDNs and browser caching. Yes, Remix prefers to bet on standards and is built around them. So how does it work?

When you render a page on the server you need to use theCache-Control header. Then you can tell the user’s browser and your CDN provider to cache this page for a specific amount of time.

And that’s it.

Yes, it’s that simple. You can cache pages that change less frequently for a longer period. Pages that change frequently, like for example your homepage, might be cached for a short time. And it’s even possible to have the ISR behaviour of regenerating pages in the background on CDN by using the stale-while-revalidate strategy. Although be careful, as not all CDN providers support it.

Taking an SSR-only approach lets Remix run on the edge. That I think is the main advantage it has over Next.js. You can use platforms like Cloudflare Workers to host your web app and get a significant performance boost paying pennies for hosting.

Data fetching

Data fetching in Next.js depends on the chosen rendering strategy:

For each of those strategies, you’ll need some data fetching library (react-query for example) to be able to re-fetch data on the client.

Remix data fetching is also tightly coupled with the page rendering strategy. Each route can implement a loader function. Its responsibility is to fetch your data and return it. Then Remix passes this data to your page. This loader runs on a server so you can directly connect to your database, call external API, read from the filesystem, or do anything you normally do on the server.

So far it sounds very similar for both frameworks. The main difference will surface when you attempt to access your data.

Next.js passes it as props to your page component.

Remix on the other side has a particular hook called useLoaderData that lets you access your data:

Did you notice? You use this hook inside of your page component. This means it already works for the client-side as well! Yes, Remix comes with a built-in solution for data fetching in both environments — server and client. Isn’t that nice?

Data mutations

Next.js doesn’t have any solutions for data mutations out of the box. You need to either create your own or use existing libraries. That means you need two things:

  1. a way to send your data mutations to your API
  2. a method for user to modify data, probably using some form library for React like Formik

Remix comes with a built-in solution. And yes, it’s also based on standards. HTML forms and HTTP. Let’s dive a bit deeper.

Every route can have an action. It’s just a function, called on the server when your route receives a request with a method other than GET. It’s like a loader, but for data mutations.

How do you call your action from the client? By using the Form component from Remix. A very simple form might look like this:

It’s very similar to a regular HTML form, back from the PHP age. There’s a reason for it. It’s a standard HTML form, but with a progressive enhancement applied. It means you can have a regular form with some fancy UI. This form might even work without any JavaScript. It’s a good, old standard HTML form with the action attribute.

In addition, Remix has two built-in hooks to help you work with data mutations:

  • useActionData — it’s like useLoaderData but for action data
  • useTransition — it gives you form as a serialised FormData (standards!) so you can check its state

Image component

Next.js has a superb component called next/image. Its key benefits are lazy loading out of the box, loading correct image sizes and loaders integration, so you can use services like Cloudinary for image hosting with no additional config.

Unfortunately, Remix doesn’t come with a solution like this. You can create your component or use an existing library. And for lazy loading, you can use the loading attribute for the IMG tag. It lines up nicely with the Remix philosophy of betting on standards, but having it out of the box would be a great addition.


Those were some of the primary differences between those two frameworks. I’m excited to see Remix impacting the React frameworks world, especially when its major goal is to create better web applications using standards. Also, the possibility to place React app at the edge is something I’m eager to try. Remix is worth trying, particularly for highly dynamic applications. It might surprise you how easy and fun it is to use.

Kacper Łukawski
Dec 8, 2021
min read