Store Bridge
A Backend-for-Frontend layer that unifies Shopify's Storefront and Admin APIs behind a single, type-safe tRPC interface — reducing client complexity and enabling edge caching.
Headless Shopify storefronts need data from multiple Shopify APIs: product data from Storefront API, inventory from Admin API, metafields from both, and custom logic for pricing rules. Frontend code becomes a tangled web of different API clients, authentication schemes, and error handling patterns.
Built a tRPC-based BFF that sits between the frontend and Shopify. It merges data from multiple Shopify APIs into unified response shapes, handles all authentication, implements edge caching strategies, and exposes a single type-safe interface that frontends consume.
1export const productRouter = router({2 getByHandle: publicProcedure3 .input(z.object({ handle: z.string() }))4 .query(async ({ input, ctx }) => {5 // Parallel fetch from both APIs6 const [storefrontData, adminData] = await Promise.all([7 ctx.storefront.query(PRODUCT_QUERY, {8 variables: { handle: input.handle },9 }),10 ctx.admin.query(INVENTORY_QUERY, {11 variables: { handle: input.handle },12 }),13 ])1415 const product = storefrontData.product16 const inventory = adminData.productByHandle1718 return {19 ...product,20 variants: product.variants.nodes.map(variant => ({21 ...variant,22 inventoryQuantity: inventory?.variants.nodes23 .find(v => v.id === variant.id)24 ?.inventoryQuantity ?? null,25 // Custom pricing logic26 finalPrice: applyPricingRules(variant, ctx.customerTags),27 })),28 }29 }),30})31
Interested in similar work?
Let's discuss how I can help bring your Shopify project to life.