All articles
Medusa.js · GraphQL · System Design

A real-time bullion pricing engine for Gold & Gems

Jewellery pricing isn't a static number — it moves with the gold spot rate every day. Here's how the pricing engine recalculates thousands of SKUs without breaking checkout or overselling inventory.

Published
Nov 4, 2025
Reading time
6 min read
Level
Deep Dive
A real-time bullion pricing engine for Gold & Gems cover

Why jewellery pricing can't be a static field

Most e-commerce pricing is a number you set and change occasionally. Gold & Gems needed the opposite: prices for gold and silver jewellery move with the daily bullion spot rate, and each product's final price is a calculation — spot rate × weight, plus making charges, plus certification fees for gemstones, plus applicable taxes — not a stored value. Storing a static price would mean re-editing every SKU on every rate change, which is not realistic across a catalog this size.

Computing price at read time, not write time

The pricing engine computes the final price at request time from the current spot rate and each product's fixed attributes (metal weight, purity, gemstone certification data, making-charge percentage). The spot rate itself is fetched and cached with a short TTL so we are not hitting a third-party rate provider on every single request, while still staying accurate to within the rate provider's own update frequency.

The harder problem: not overselling

High-value, often one-of-a-kind gemstone pieces make overselling expensive and reputationally damaging in a way a $20 t-shirt SKU is not. Inventory reservations use ACID-compliant transactions so a checkout hold on a unique piece is atomic across the physical showroom point-of-sale system and the online store — the two can never both believe the same physical item is available.

Why GraphQL over plain REST here

The storefront needed to request different shapes of the same product data depending on context (a compact card on a listing page versus a full detail page with certification documents and price breakdown). REST would have meant either over-fetching on the listing view or maintaining several bespoke endpoints. A GraphQL schema with resolvers scoped to the actual fields each view needs kept mobile payload sizes down without duplicating endpoint logic.

What surprised me

The pricing calculation itself was the easy part. The genuinely hard part was making the multi-branch inventory reservation logic correct under concurrent access — two showroom staff and one online customer all trying to reserve the same unique ring within the same few seconds is a real scenario at this scale, and it is where most of the engineering time actually went.

More articles