Comprehensive guides covering Remix patterns, optimization techniques, and developer shortcuts. Plus code snippets and prompts to speed up your workflow.
If you're like me, you've probably been living comfortably in the Next.js ecosystem for a while now. The App Router, Server Components, and the familiar file-based routing have become second nature. But recently, I found myself diving into the Shopify ecosystem for a new project, and guess what? They're all-in on Remix.
At first, I'll admit, I was a bit skeptical. "Another React framework? Really?" But after spending some quality time with Remix, I've discovered it's not just different—it's refreshingly different. The way it handles server-side logic, data fetching, and forms feels both familiar and completely new at the same time.
The transition wasn't without its learning curve, though. There were moments where I found myself reaching for patterns that simply don't exist in Remix, and other times where I was amazed by how elegantly Remix solved problems I didn't even know I had.
What You'll Learn
In this article, we'll explore the key conceptual differences between Next.js and Remix that every Next.js developer needs to understand to work effectively with Remix. I've ranked these differences by their impact on your day-to-day development and how much mental adjustment they require.
We'll cover:
Server-side logic boundaries - Where and how you write server code
Data fetching patterns - Moving from various approaches to Remix's loader-centric model
Routing philosophy - Single-file routes vs. Next.js's separation of concerns
Form handling - Embracing progressive enhancement over pure client-side logic
Dynamic routing - Similar concepts, different implementation
Client-side data fetching - When and how to break out of the server-first pattern
Layout patterns - Flexible outlet-based layouts vs. Next.js's structured approach
API endpoints - Resource routes vs. traditional API routes
HTTP method handling - Working within HTML form constraints
By the end, you'll have a solid mental model for thinking in Remix terms and understand why so many developers (and companies like Shopify) are gravitating toward this approach.
Let's dive in!
1. Server-Side Logic Location & Boundaries
Impact: HIGH | Learning Curve: MEDIUM | Philosophy: FUNDAMENTAL
This is probably the biggest mindset shift you'll encounter. In Next.js, you have multiple ways to write server-side code, and the boundaries can feel a bit blurred. Remix takes a much more opinionated approach.
The key insight here is that Remix makes the server/client boundary crystal clear: if it's in a loader or action, it runs on the server. Everything else is client-side.
2. Data Fetching Patterns
Impact: HIGH | Learning Curve: HIGH | Philosophy: FUNDAMENTAL
Next.js gives you multiple ways to fetch data, which can be both a blessing and a curse. Remix simplifies this with a single, consistent pattern.
The beauty of Remix's approach is its predictability. Every route that needs data has a loader, and every component gets that data via useLoaderData(). No guessing about where the data comes from or how it's fetched.
3. Routing Philosophy & File Structure
Impact: HIGH | Learning Curve: MEDIUM | Philosophy: MODERATE
Next.js separates concerns with different file types, while Remix embraces the single-file-per-route approach.
app/routes/
app.tsx // Layout route
app._index.tsx // Index route for /app
app.posts.tsx // /app/posts
app.posts.$id.tsx // /app/posts/:id
api.posts.ts // Resource route (no UI)
Remix's dot notation for nested routes takes some getting used to, but it's incredibly powerful once you grasp it. A single file can contain your layout, data loading, actions, and component—everything related to that route.
4. Form Handling & Mutations
Impact: HIGH | Learning Curve: MEDIUM | Philosophy: MODERATE
This is where Remix really shines. While Next.js has embraced Server Actions, Remix's approach to forms feels more native to the web platform.
// Multiple forms on same page hitting different routesexportdefaultfunctionProductsPage() {
const addFetcher = useFetcher();
const removeFetcher = useFetcher();
return (
<div>
{/* Posts to /products/add action */}
<addFetcher.Formmethod="post"action="/products/add"><inputname="name" /><buttontype="submit">Add</button></addFetcher.Form>
{/* Posts to /products/remove action */}
<removeFetcher.Formmethod="post"action="/products/remove"><inputname="intent"value="delete"type="hidden" /><inputname="id" /><buttontype="submit">Remove</button></removeFetcher.Form></div>
);
}
The useFetcher hook is incredibly powerful—it lets you have multiple forms on the same page, each with their own loading states and error handling, all while maintaining progressive enhancement.
5. Dynamic Route Parameters
Impact: MEDIUM | Learning Curve: LOW | Philosophy: MODERATE
Both frameworks handle dynamic routes well, but the syntax differs slightly.
Since HTML forms only support GET and POST, Remix uses conventions like intent to differentiate between different actions.
Key Takeaways for Next.js Developers
Server boundaries are file-based: No more "use server" directives. If it's in a loader or action, it runs on the server.
Data flows through loaders: Every route that needs data has a loader, and components consume that data via useLoaderData().
Embrace progressive enhancement: Remix's <Form> component works without JavaScript, then enhances the experience when JS loads.
One file per route: A single route file can handle data loading, mutations, and UI—no need to separate concerns across multiple files.
useFetcher is your friend: For complex interactions, multiple forms, or cross-route communication, useFetcher is incredibly powerful.
The learning curve is moderate because the core React concepts remain the same, but the patterns are different enough to require some mental adjustment. Once you embrace Remix's philosophy of staying closer to web standards, you'll find it's a refreshing take on full-stack React development.
Give it a try on your next project—you might be surprised by how much you enjoy the clarity and simplicity of Remix's approach!