When building large Hydrogen projects, component files can quickly become monolithic if data fetching, Shopify Storefront API bindings, and visual styling are tightly coupled inside single route files.
Here is a recommended folder structure and design pattern for keeping Hydrogen components modular, reusable, and easy to maintain across multiple pages:
Recommended Project Layout:
app/
├── components/
│ ├── ui/ # Presentational components (Button, Input, Badge)
│ ├── sections/ # Page sections (Hero, FeaturedCollection, ProductGrid)
│ └── global/ # Header, Footer, CartDrawer
├── fragments/ # Colocated GraphQL fragment queries
└── routes/ # Remix route handlers
Pattern: Decoupling Presentational UI from Data Loaders
To ensure a section (e.g., FeaturedCollection) can be reused anywhere (Homepage, PDP, custom landing pages), pass raw API node data as props rather than binding routes to hardcoded queries:
// app/components/sections/FeaturedCollection.tsx
import { ProductCard } from '~/components/ui/ProductCard';
export function FeaturedCollection({ title, products, layout = 'grid' }) {
if (!products?.length) return null;
return (
<section className="py-12 px-4 max-w-7xl mx-auto">
<h2 className="text-2xl font-bold mb-6">{title}</h2>
<div className={layout === 'grid' ? 'grid grid-cols-2 md:grid-cols-4 gap-6' : 'flex overflow-x-auto gap-4'}>
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
</section>
);
}
This clean boundary allows developers to drop FeaturedCollection into any route loader outcome or CMS component renderer effortlessly.