Dwarves
Memo
Type ESC to close search bar

Remix Versus Nextjs

A brief comparison between Remix and Next.js frameworks

Introduction of Remix

Remix describes itself as:

Remix is an edge native, full-stack JavaScript framework for building modern, fast, and resilient user experiences. It unifies the client and server with web standards so you can think less about code and more about your product.

Compared to Next.js, which is one of the most React frameworks used for server-side rendering and has been there for a significant time, Remix appears as a new strong competitor. Developers have started to wonder what the difference between these two frameworks is.

In this post, we will mainly focus on Remix and highlight what makes it unique and where it shines the most.

How is Remix different from Next.js?

Page rendering strategies

Despite the same idea of creating websites that are rendered on the server before being sent to the client, Remix and Next.js go with distinct approaches.

Remix doesn’t support Static Site Generation (SSG) but it suggests using HTTP stale-while-revalidate caching directive (SWR) as an alternative. The key here is that static routes are cached using a CDN. These routes are then served to users on each visit and automatically revalidated for the next visitor.

Routing

Both Remix and Next.js follow a file-based routing system.

In Next.js, each file inside the /pages directory will be automatically set as a route.

pages/index.js ==> /
pages/users/index.js ==> /users
pages/users/create.js ==> /users/create

Remix also does the same but the route directory is /app/routes:

app/routes/index.js ==> /
app/routes/users/index.js ==> /users
app/routes/users/create.js ==> /users/create

Built on top of React Router, Remix shines when it comes to nested routing. It comes with a very powerful route nesting mechanism that can put one or many routes inside another route and those act like children components that can be mounted and unmounted depending on the active URL path. We need to use an Outlet component to render the route hierarchy from the parent routes.

Next.js, on the other hand, comes with its own router and has support for routes nesting but it’s not so easy to do so compared to Remix.

Data Loading

Next.js supports different ways for loading data on the server-side like getServerSideProps and getStaticProps based on the type of web app.

Remix has a new concept with two portions:

import { useLoaderData } from "remix";

export const loader = () => {
  // fetch data from database or make API calls
  return {data}
};

export default function App() {
 // get access to data
  let {data} = useLoaderData();

  return (
    <div>
      <p>Use Data in component {data}</h1>
    </div>
  );
}

Data Mutation

Next.js doesn’t do anything for mutations. Basically, we would have to handle everything from creating a form, fetching data, managing state, adding event handlers, to finally dealing with errors, interruptions, and race conditions.

Data mutations in Remix are built on top of two fundamental web APIs: <form> and HTTP. All we have to do is to use a <Form> component (works identically to <form> with a couple of extra goodies for optimistic UI etc.) and a route function named action. When the user submits a form, Remix with call the action for the form and reload all of the data on the page. This ensures that any updates to the data are reflected in the UI.

export const action = async ({ request }) => {
  const form = await request.formData()
  const content = form.get('content')
  return redirect('/')
}

export default function App() {
  return (
    <div>
      <Form method="POST">
        <label htmlFor="content">
          Content: <textarea name="content" />
        </label>
        <input type="submit" value="Add New" />
      </Form>
    </div>
  )
}

Error Handling

Next.js define some custom pages for certain status errors like 404 or 500 errors. However, some errors around data and rendering are not supported.

Remix has an error boundary for handling errors. When we create a route component, we can also define an error boundary for catching any errors that occur in the route component. It likes having two components in a route file, with one being the actual route component and one being the fallback when errors happen in the former. One noteworthy thing is when there is an error in a nested component route and this route has no error boundary, the error bubbles up the nested tree until caught by a parent’s error boundary.

Conclusion

For React developers, Next.js is obviously the prior choice when it comes to server-side rendering for its familiar concepts and larger community. Has been around for a while, it seems like a steady pedestal and is not easy to be replaced in a short period.

Even so, Remix looks like a shiny new thing. It also provides a higher level of abstraction. Routing system might be confusing but it is a remarkable feature too. Other built-in features such as data loading, data mutations, error boundary, etc. actually improve the developer experience.

Overall, Remix is a new framework, and it will definitely become more powerful and widespread in the future.