EDS Commerce Storefront
The EDS Commerce Storefront is a pre-built set of blocks that turn an EDS site into a fully functioning ecommerce storefront. The storefront is the render and delivery layer; an Adobe Commerce (Magento) instance or a third-party commerce API holds the catalog, prices, cart, and orders.
EDS gives you Lighthouse-100 product pages and instant-purge after price / inventory changes; the commerce backend gives you SKUs, taxes, and orders. The split keeps each side focused.
Architecture
Two flows:
- Catalog reads - PLP and PDP shells (marketing copy, layout, imagery) are served as cached HTML from the edge, then product data is hydrated from the catalog API. Edge responses carry surrogate keys per SKU / category so a price or inventory change purges only the affected pages.
- Cart and checkout - the surrounding page shell (nav, footer, layout) is served from the
same cached edge HTML as any other page. The cart/checkout state itself - items, totals,
and provider-issued payment tokens - lives in the browser and talks directly to the commerce
API. Raw card details should never touch your own JS or browser storage - collect them through
provider-hosted fields (e.g. Adobe Commerce/Stripe Elements-style iframes) that tokenize directly
with the payment provider. Any personalized cart/checkout response must be sent with
Cache-Control: private, no-storeand never cached at the edge.
Block library
The Commerce Storefront ships a set of blocks under adobe-commerce/storefront-eds:
| Block | Purpose |
|---|---|
product-list-page | Category / search results page (PLP) |
product-details | Product detail page (PDP) |
cart | Mini-cart and full cart |
checkout | Multi-step checkout (shipping, payment, review) |
account | Customer account, addresses, orders |
commerce-search | Live search bar with autocomplete |
recommendations | "You may also like" widgets |
These behave like normal blocks - folder under /blocks/, decorate function, scoped
CSS - but most of them call the commerce API at decoration time.
Talking to the catalog
Adobe Commerce exposes catalog data via GraphQL. The storefront blocks issue GraphQL queries from the browser:
const query = `
query Product($sku: String!) {
products(filter: { sku: { eq: $sku } }) {
items {
sku
price_range { minimum_price { final_price { value currency } } }
stock_status
}
}
}
`;
export default async function decorate(block) {
const sku = block.dataset.sku;
// name, description, and images are SEO-critical and already present in the
// pre-rendered HTML (see below) - this call only refreshes genuinely dynamic
// state: live price and stock.
const res = await fetch(`https://commerce.example.com/graphql`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables: { sku } }),
});
let payload;
try {
payload = res.ok ? await res.json() : null;
} catch {
payload = null;
}
const product = payload && !payload.errors
? payload.data?.products?.items?.[0]
: null;
if (!product) {
renderUnavailable(block);
return;
}
renderPriceAndStock(block, product);
}
For SEO-critical fields (title, description, canonical URL, JSON-LD), render them into the cached HTML at author time rather than fetching client-side. Reserve the runtime GraphQL call for genuinely dynamic state - live inventory, per-user pricing, or personalised recommendations.
Caching strategy
| Data | Cached where | Invalidation |
|---|---|---|
| PDP HTML | Edge (long TTL) | Surrogate key per SKU; commerce events purge on change |
| PLP HTML | Edge (medium TTL) | Surrogate key per category |
| Cart state | Browser (sessionStorage) + commerce API | Live |
| Customer account | Commerce API only (never cached) | Live |
| Recommendations | Edge (short TTL or async) | Time-based |
Surrogate keys are sent on the response and used by the Admin API
/cache endpoint to purge precisely when inventory or price changes.
Authentication
Customer auth is not the EDS site's concern - the commerce API issues tokens.
The storefront block stores the token in sessionStorage (or localStorage for
"remember me") and adds it to subsequent calls.
Sensitive operations (order history, address book) must run client-side against the commerce API; never embed customer-specific data in cached HTML.
SEO
Commerce sites live and die by SEO. The storefront blocks emit:
- Per-product
<title>, meta description, canonical URL - JSON-LD structured data (
Product,Offer,AggregateRating) - OG tags for social sharing
- A real
<h1>per page (not built from JS) - Sitemap entries via
helix-query.yaml
Aim for the catalog to be fully crawlable without running JS.
Performance
Two regressions to watch:
- PLP page weight - a list of 24 products with full image carousels can blow
the Lighthouse budget. Use
loading="lazy"on below-the-fold images and only render the first image of each product card. - GraphQL waterfall - if a block fetches data in
decorate()and another block downstream needs the same data, hoist the fetch intoscripts.jsso it runs once.
Adobe Commerce vs third-party backends
The storefront blocks are written against Adobe Commerce GraphQL, but the layer is thin enough to swap. Common substitutions:
| Backend | Adapter strategy |
|---|---|
| Adobe Commerce | Use as-is |
| commercetools | Replace the GraphQL client with the commercetools SDK; map their Product to the Adobe shape |
| Shopify | Use the Storefront API; map ProductVariant to Product |
| Custom REST | Wrap each block's data fetch in a thin adapter |
Common gotchas
| Symptom | Likely cause | Fix |
|---|---|---|
| PDP shows stale price | Surrogate key not configured | Set Surrogate-Key: sku-{sku} from the upstream and purge on price change |
| Cart icon shows wrong count | sessionStorage out of sync with API | Reconcile from API on every page load |
| PLP "out of stock" missing | Inventory not in cached HTML | Either render inventory in HTML and purge on change, or hide it client-side |
| GraphQL errors on every page | API origin not in CSP | Add the commerce origin to Content-Security-Policy.connect-src in helix-config.yaml |
See also
- Blocks - the storefront blocks follow standard conventions
- Customizing - CSP for the commerce API origin
- Admin API - surrogate-key purges
- Adobe docs: Commerce Storefront on EDS