Skip to content
OCTANE LABS
Mountain Gap Coffee: A Hand-Built Shopify Theme for a Roast-to-Order Coffee Company

Mountain Gap Coffee: A Hand-Built Shopify Theme for a Roast-to-Order Coffee Company

Specialty Coffee / E-commerce (DTC + Wholesale)

A custom-built Shopify storefront for a specialty coffee roaster — a heavily reworked Dawn theme with metafield-driven coffee product pages, a roast-to-order fulfillment flow, a wholesale acquisition funnel, and structured data throughout, shipped with zero build step and theme-quality checks enforced in CI.

What was the problem?

Mountain Gap Coffee is a specialty roaster with two jobs a stock Shopify theme handles badly. First, coffee is a detail-driven product — origin, region, process, varietals, altitude, roast level, tasting notes — and off-the-shelf product templates have nowhere to put any of it. Second, the company sells both retail bags to individual drinkers and wholesale coffee to cafés, offices, restaurants, and grocers, and its Shopify plan doesn't include native B2B tooling. On top of that, everything ships roast-to-order: the store needs to represent freshness honestly and be able to pause ordering around the roast schedule without breaking the storefront. A generic theme, or a bought premium theme, would have meant fighting the tool on every one of those fronts.

How did we approach it?

We reworked Shopify's Dawn reference theme rather than going headless or bolting on apps. Staying on Dawn keeps Mountain Gap on Shopify's supported upgrade path — Online Store 2.0, Liquid, JSON section templates, the native checkout and admin — while we replace the parts that matter with bespoke, coffee-specific sections and snippets built on top. The coffee product model is driven entirely by metafields, not hardcoded copy. A single spec-table snippet reads the custom.* namespace and renders origin, process, roast, and tasting-note data row by row — each row guarded on its own metafield, so a rich single-origin shows a full table while the canister or a gift card renders nothing at all. Format chips are derived from variant titles, not entered by hand. That means the roaster edits products, not code, and every non-coffee product degrades cleanly on its own. We kept the customization maintainable and honest: coffee behavior lives in its own sections and snippets rather than as overrides scattered through Dawn, the one place we suppress a linter rule is documented and narrowly scoped to a stock Dawn pattern, and structured data is kept verbatim-synced to the visible on-page copy. And we held a "just a theme" project to real engineering discipline — Theme Check, Prettier, and an automated theme-quality CI gate all run on every push through GitHub Actions, with no build step to rot and vanilla JavaScript loaded only where a section needs it.

What did we deliver?

- A custom brand theme reworked from Shopify's Dawn 13.0.0 — Fraunces headings +
Work Sans body, with bespoke hero-video, start-here, trust-strip, CTA-band, and
page-hero sections replacing Dawn's stock merchandising
- Metafield-driven coffee product pages: a full-disclosure spec table (origin,
region, process, varietals, altitude, harvest, roast level, tasting notes) plus
format chips (whole bean / ground / K-Cups) and tasting-note pills — every row
guarded on its own metafield so non-coffee products degrade cleanly
- A roast-to-order / pre-order product flow with a reversible store-pause toggle
and an "ordering paused" banner, built around fresh-roast fulfillment
- A coffee-only grouped collection page with a sticky category tab bar and live,
client-side filtering (its own section, kept separate from Dawn's default grid)
- A wholesale acquisition page (landing + FAQ) that routes qualified buyers into
BeanLink, the roaster's wholesale platform, with its own Service + FAQPage +
BreadcrumbList structured data
- Structured data across the store — FAQPage, HowTo (brew guides), Product,
Organization, and BreadcrumbList JSON-LD — kept verbatim-synced to on-page copy
for search and AI-answer visibility
- Content architecture: how-we-roast, our-story, brewing hub with recipe primers,
and an FAQ, each on custom sections rather than generic page templates
- Engineering discipline for a theme project: Theme Check linting, Prettier
formatting, and an automated theme-quality CI gate running on every push via
GitHub Actions — no build step, vanilla JS loaded only where needed

What was the outcome?

Mountain Gap Coffee runs on a storefront that was built for coffee, not stretched to fit it. Retail shoppers get the origin, process, and tasting detail specialty buyers expect before they add to cart; the roaster manages all of it by editing product metafields, never the theme. Roast-to-order fulfillment is represented honestly, and ordering can be paused and resumed around the roast schedule without touching code. Wholesale buyers get a real path in — a dedicated landing page and FAQ that route them into BeanLink — without Mountain Gap paying up to a higher Shopify plan for native B2B tooling. Under the hood, the build is deliberately lean: a custom Dawn fork with no bundler, vanilla JavaScript loaded only where it's needed, and component-scoped CSS. Every push runs Theme Check and an automated theme-quality CI gate, so regressions are caught before they ship rather than discovered in production.

Results

ci
GitHub Actions — Theme Check + automated theme-quality CI gate on every push
build_step
None — vanilla JavaScript + component-scoped CSS, no bundler
theme_base
Shopify Dawn 13.0.0 (custom fork)
typography
Fraunces (headings) + Work Sans (body)
structured_data
FAQPage, HowTo, Product, Organization, Service, BreadcrumbList JSON-LD
coffee_data_model
Product metafields (custom.* namespace: country, region, category, producers, process, varietals, harvest, altitude, roast_level, tasting_notes, is_limited)

Tech stack

  • Shopify
  • Online Store 2.0
  • Liquid
  • Dawn 13.0.0 (custom fork)
  • Vanilla JavaScript
  • CSS
  • Schema.org JSON-LD
  • GitHub Actions CI

Want results like these?

Tell us about your project and we'll walk through how we'd approach it.