Last year we released Hydrogen, our React-based framework for building custom storefronts. Hydrogen allows developers to build fast, dynamic commerce experiences by leveraging streaming server-side rendering, React Server Components, and caching APIs. Hydrogen is currently in developer preview and I'm excited to show you how you can rapidly build out a simple product page by leaning on Hydrogen's components.

Previously, constructing a custom storefront required developers to manually manipulate data and create custom components for each page. Hydrogen accelerates this process by offering Shopify-specific commerce components, hooks, and utilities that allows developers to focus on building unique storefront experiences.
Getting Started
To get started, generate a starter app by heading to hydrogen.new.
Most of the files you’ll work with are located in the /src
directory. This directory contains a set of boilerplate components and pages, the main app component (App.server.jsx
), and the client/server entry points. For an in-depth overview, see the getting started guide.
The starter app is connected to a demo store which contains a few products. You can find the details in /shopify.config.js
.
Hydrogen connects the Storefront API (with the access token already configured) and allows us to fetch data from descending server components using the useShopQuery
hook.
Hydrogen's starter app comes with a convenient out-of-the-box product page. To get hands-on with the components and understand the moving parts, we'll put this page aside and build our own.
Our goal is to set up a Product Context that allows us to render product details with ease:
From there, we'll create a variant picker and allow the customer to add the product to cart.
Creating a Product Page
In your app, create a new page /src/pages/featured.server.jsx
with the following code:
Hydrogen's file based routing kicks in, and a new route is created at /featured
. This code will be rendered on the server because the filename ends in .server.jsx
. Our page is wrapped in the starter app's Layout
component that has a cart ready to go.

We'll be using a ProductProvider
component (alias: Product
) to set up a context with product details. This allows descendents to use components like Product.title
(rendering the product title) and hooks like useProductOptions
(keeping track of the selected variant). Our product page requires client-side state, so we'll create a /src/components/FeaturedProductDetails.client.jsx
client component to house product details.
You'll notice ProductProvider
requires a Product object to be passed through as a prop. Instead of manually writing a query to fetch all of the required fields, many Hydrogen components (including this one) have GraphQL fragments that you can use instead. It's important to note that this fragment includes variables that you’ll need to provide values for when performing the query. Joining these pieces together, the /src/pages/featured.server.jsx
file looks like this:
And the /src/components/FeaturedProductDetails.client.jsx
file looks like this:
The featured product page now shows a product title wrapped in the starter app layout.

With the context in place, it's a breeze to build out the rest of the page—try adding a product description, price, or custom component like handle (hint: you'll need to import Hydrogen's useProduct
hook!):
Customizing Components
Hydrogen components are customized using passthrough and render props. Using passthrough props, you pass attributes as props to the component that passes them through to the rendered HTML tag:
<Product.Price className="font-bold" aria-live="polite" />
And the output is:
<div class="font-bold" aria-live="polite">$749.95</div>
Using render props, you pass a function that returns JSX as a child to the Hydrogen component:
<Product.Price>
{({ amount, currencySymbol }) => `Fancy price: ${currencySymbol}${amount}`}
</Product.Price>
And the output is:
<div>Fancy price: $749.95</div>
Adding a Variant Picker
Merchants add variants to products that come in more than one option, such as color. To accommodate these, we'll need a variant picker dropdown. We can use the useProduct
hook to retrieve a list of variants and get/set for the selected variant. A simple dropdown is created by mapping the variants. When a selection is made, setSelectedVariant updates the state:
To set the initial variant, pass the product provider an initialVariantId
property. This is a good place to use the flattenConnection
utility that transforms a connection object from the Storefront API into a flat array of nodes:

Adding the Add to Cart Button
The Product.SelectedVariant.AddToCartButton
component knows which variant is selected and takes care of adding the item to cart. We can expand on this further by toggling a disabled state and changing the text based on a variant's availability:
Finishing Touches
With a functioning product page in place, we now add a variant image (you guessed it, there’s a component for that too) and tidy up the styling:
The final code is found on StackBlitz.

Hydrogen Enables Rapid Development
Taking advantage of these components, hooks, utilities, and fragments allows you to skip many of the repetitive and mundane parts of building a custom storefront, speeding up the development process.
For more code examples, be sure to examine the starter template which provides a full purchase journey out-of-the-box. You can find these files in the /src directory of your project.
This post just scratched the surface, check out all of the components and take Hydrogen for a spin on your next project!
Scott’s a Developer Advocate at Shopify, located on the east coast of Australia and formerly a Shopify app developer and developer bootcamp coach. When he's not tinkering with code, you'll find him checking the surf or hanging out with his family.
Wherever you are, your next journey starts here! If building systems from the ground up to solve real-world problems interests you, our Engineering blog has stories about other challenges we have encountered. Intrigued? Visit our Engineering career page to find out about our open positions and learn about Digital by Default.