
Photo by Alex Knight on Unsplash
Remix Ecommerce Templates: Progressive Enhancement for D2C Stores
Remix Ecommerce Templates: Progressive Enhancement for D2C Stores
Remix is the React framework built around the web platform. Forms work without JavaScript, data flows through explicit loader and action functions, and nested routes share data without refetching. For ecommerce teams that value progressive enhancement and explicit data loading over implicit server components, Remix is a meaningfully different choice from Next.js — and in some cases, the better one.
Note: as of late 2024, Remix merged into React Router v7 and the framework now officially runs under the "React Router framework mode" banner. MVPHub templates still call it "Remix" because the loader/action data pattern is what defines the framework shape, not the brand name.
TL;DR
- Loaders fetch data server-side, actions handle form submissions — a single mental model for every data concern
- Forms work without JavaScript by default — progressive enhancement is the baseline, not an afterthought
- Nested routes share data across segments automatically — great for category → subcategory → product hierarchies
- React 19 under the hood — all the React ecosystem wins still apply
- Smaller ecosystem than Next.js — fewer tutorials, fewer pre-built integrations
- Pick Remix when you value the data model AND you're building form-heavy flows (B2B, multi-step checkout, account management)
Browse Remix ecommerce templates
The data model
Remix has three primitives for every route:
loader— runs on the server when a GET request hits this route. Returns data the component renders.action— runs on the server when a form POST/PUT/DELETE hits this route. Handles mutations.- Default export (component) — renders UI using
loaderdata and submits forms toaction.
That's it. Every route in a Remix app is a combination of these three things, and data flows through them predictably.
Example: product detail page
// app/routes/products.$handle.tsx
import type { LoaderFunctionArgs, ActionFunctionArgs } from 'react-router';
import { useLoaderData, Form } from 'react-router';
import { medusa } from '~/lib/medusa';
import { getCartFromCookie, addToCart } from '~/lib/cart';
export async function loader({ params }: LoaderFunctionArgs) {
const product = await medusa.products.retrieve(params.handle);
if (!product) {
throw new Response('Not found', { status: 404 });
}
return { product };
}
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const variantId = formData.get('variantId') as string;
const quantity = Number(formData.get('quantity'));
const cartId = await getCartFromCookie(request);
await addToCart({ cartId, variantId, quantity });
return { success: true };
}
export default function ProductDetail() {
const { product } = useLoaderData<typeof loader>();
return (
<article>
<h1>{product.title}</h1>
<ProductGallery images={product.images} />
<Form method="post">
<input type="hidden" name="variantId" value={product.variants[0].id} />
<input type="number" name="quantity" defaultValue={1} min={1} />
<button type="submit">Add to Cart</button>
</Form>
</article>
);
}
What's happening:
- The
loaderruns on the server during initial render and on client-side navigations - The
actionruns when the form submits — either as a full-page POST (if JS is disabled) or as a background fetch (if JS is enabled) - The component reads data via
useLoaderDataand submits via a standard HTML<Form> - Remix automatically refetches the loader after a successful action, so the page reflects the new state
This is a fundamentally different mental model from Next.js server components + server actions. Some teams love it; some find it rigid. Build a prototype before committing.
Why progressive enhancement matters
A progressively-enhanced store stays functional when JavaScript is unavailable. That sounds like an edge case but in practice it matters for:
- Users on corporate networks that strip JavaScript for security
- Users on unreliable mobile connections where JS may fail to load
- Accessibility tools (screen readers, text-based browsers) that work better with semantic HTML forms
- Search engines that prefer fully-functional HTML over JS-dependent interactions
- Uptime resilience — if your JavaScript CDN goes down, your store keeps working
Next.js server components don't give you progressive enhancement for free. You can build it, but the default path is "JavaScript required." Remix inverts the default: stores work without JavaScript, and JavaScript enhances them.
Nested routing and shared data
Remix's nested routing is the other killer feature for ecommerce. Consider a URL like /shop/fashion/shirts/classic-white-tee:
app/routes/
shop.tsx # Shared "shop" layout
shop.$category.tsx # Category layout — shows sidebar
shop.$category.$subcategory.tsx # Subcategory breadcrumbs + filters
shop.$category.$subcategory.$handle.tsx # Product detail
Each nested route has its own loader. When a user navigates to the product page, Remix runs all 4 loaders in parallel and shares their data across nested components. Clicking to a different product in the same subcategory only re-runs the product loader — the category and subcategory data is already loaded.
This is much cleaner than Next.js's approach of either duplicating data fetches at every level or threading data through component props.
Remix vs Next.js: when to pick which
| Scenario | Remix | Next.js |
|---|---|---|
| Form-heavy flows (B2B, multi-step checkout) | ✓ | · |
| Progressive enhancement required | ✓ | (possible but not default) |
| Biggest React ecosystem | · | ✓ |
| Hiring pool size | Medium | Largest |
| Nested routing with shared data | ✓ | (App Router has parallel routes) |
| Server components fine-grained control | · | ✓ |
| Turnkey Vercel deployment story | · | ✓ |
| Multi-cloud / Cloudflare deployment | ✓ (Node-compatible) | ✓ (more options) |
Pick Remix when:
- You value the explicit loader/action data model
- Your store has lots of forms (filters, account management, multi-step checkout)
- Progressive enhancement is a hard requirement
- Your team prefers explicit data flow over implicit server component conventions
Pick Next.js when:
- You want the biggest React ecosystem
- Your team is already productive in Next.js App Router
- You need a specific Next.js-only integration
- You value the largest hiring pool
Architecture: Remix + Medusa
MVPHub Remix templates ship with a Medusa v2 backend integration.
app/
routes/
_layout.tsx # Root layout (header, footer, cart drawer)
_index.tsx # Homepage
products.$handle.tsx # Product detail — loader fetches, action adds to cart
collections.$handle.tsx # Collection browse — loader fetches products with pagination
cart.tsx # Cart page — loader fetches cart, action updates quantities
checkout.tsx # Checkout — loader fetches cart, action creates Stripe session
account.tsx # Account layout
account._index.tsx # Account overview
account.orders.tsx # Order list
account.orders.$orderId.tsx # Order detail
lib/
medusa.server.ts # Server-only Medusa client
session.server.ts # Cookie session helpers
Every interaction uses a form. Every data read uses a loader. The data flow is uniform across the whole app.
Common questions
Is Remix still a separate framework or part of React Router?
As of React Router v7 (late 2024), Remix merged into React Router and is now "React Router framework mode." For practical purposes MVPHub templates still use the "Remix" name because the loader/action data pattern is what matters, and the docs for both names describe the same concepts.
How does Remix compare to Next.js App Router?
Both are React SSR frameworks with server-side data fetching. The key differences:
- Data model: Remix uses loaders (for reads) and actions (for mutations) as top-level route exports. Next.js App Router uses server components (for reads) and server actions (for mutations).
- Progressive enhancement: Remix gives you this for free via
<Form>. Next.js requires you to build it. - Ecosystem: Next.js has more libraries, tutorials, and third-party integrations.
- Hosting: Both deploy to Vercel, Cloudflare, Netlify, and self-hosted Node. Next.js has more platform-specific optimizations.
Can I use Remix without JavaScript?
Yes, and that's the point. Every core ecommerce interaction (browse, filter, add to cart, checkout) works via standard HTML forms. JavaScript enhances them with smoother UX and client-side navigation, but the site doesn't break without it.
Does Remix support ISR?
Not as a first-class primitive like Next.js ISR. Remix relies on HTTP cache headers — you set Cache-Control on the response and the CDN handles revalidation. For most ecommerce stores this is functionally equivalent.
Can I use Remix with any backend?
Yes. Remix is a frontend framework — loaders can call any API. MVPHub Remix templates ship with Medusa by default but swapping to Shopify Storefront API, BigCommerce, WooCommerce, or a custom backend is a small change in the lib/medusa.server.ts module.
Next steps
- Browse Remix ecommerce templates
- Framework comparison guide
- Next.js templates for comparison
- Template Finder quiz — guided recommendation
- Performance benchmarks
- Compatibility matrix
Remix's loader/action model is the right call when you value explicit data flow and progressive enhancement. For teams that appreciate the philosophy, it produces stores that are easier to maintain and more resilient than their Next.js counterparts. For teams that don't, it feels rigid. Try the prototype before committing to the philosophy.







