Duskel Start a project
Blog/Product Engineering

Where Shopify stops being customizable

Is Shopify customizable? Yes, in three of its four layers — and deliberately fenced in the fourth. Here's how to tell which layer your requirement lands in before you pay for the wrong estimate.

Duskel·15 Aug 2026·6 min read·Product Engineering

A client once approved a build to show contract-specific pricing on the checkout summary line. It was two sentences in the requirements doc. Nine weeks later the answer was: not on this plan, not in that layer, not at any price — the number had to be computed the night before, written to a customer metafield, and read back by a discount Function that is forbidden from making a network call. The requirement was never hard. It was filed in the wrong layer.

"Is Shopify customizable" almost never means what it says. It means: can this platform do the specific weird thing my business does — per-customer contract pricing, a product configurator, a B2B approval gate before checkout, shipping quoted live from a 3PL. Shopify is genuinely customizable in three of its four layers and fenced by design in the fourth, and the fence is invisible from the sales call. Teams find it around week six, which is exactly when it costs the most to find.

Find out which layer your requirement lives in

The theme layer is Liquid, Online Store 2.0 sections, app blocks, and theme app extensions. Presentation and merchandising belong here, and it is the cheapest ground you will ever build on because nothing needs a server, a deploy pipeline, or an uptime story. The app layer is your own service talking to the Admin GraphQL API, subscribing to webhooks, and rendering embedded admin UI through App Bridge. ERP syncs, approval workflows, custom reporting, anything holding state — that is an app, and an app is ordinary software you already know how to write and host.

The Function layer is where the platform stops behaving like a normal web stack. Discounts, cart transforms, bundles, and delivery and payment customization compile to WebAssembly and execute inside Shopify's request path, not on your infrastructure. Checkout is the walled garden: Checkout UI extensions at defined extension points, a branding API, and nothing else. Sort every line of the requirements doc into one of the four before you quote. The same sentence — "show the customer their negotiated price" — is three days in the theme, three weeks as an app plus Function, and a plan upgrade at checkout. That spread is roughly ten to one, and it is the entire estimate.

Checkout is closed, and Functions can't phone home

checkout.liquid is gone. Information, shipping, and payment steps stopped rendering it in August 2024; thank-you and order status followed in August 2025, and Shopify Scripts retired on the same schedule. What replaced them is narrower on purpose: UI extensions run in a sandboxed worker with no arbitrary DOM access, no third-party script tags, and a fixed set of render targets you cannot add to. Payment and delivery customizations are Plus-only. So "hide cash on delivery for wholesale accounts" is not an engineering question — it is a plan question, and the answer is roughly $2,000 a month.

Functions are fast because they are sealed: no network access, a hard instruction budget, deterministic execution, and an input contract you declare as a GraphQL query against the cart. Pricing that depends on a live call to your ERP therefore cannot be computed while the buyer waits. You precompute it, write it to a metafield on the customer or the variant, and let the Function read it. Pull the decision forward, cache the answer where Shopify can already see it. That redesign is the single most common rework we do on Shopify projects, and it costs a design meeting up front or a month of rebuild in discovery.

A custom app is a distribution choice, not a code style

Shopify does allow custom app development, and two different things share that name. The admin-created app under Settings hands you an Admin API access token in about ten seconds — right for an internal sync script, useless the moment you need UI or extensions, because it cannot carry either. The other kind is a CLI-built app with custom distribution: full extension support, embedded admin surfaces, installed to exactly one store via a link, no App Store review, no listing copy, no screenshots of a client's dashboard sent to a reviewer in another timezone.

The trade-off is worth knowing before you pick, because it is load-bearing. Custom-distribution apps cannot use Shopify's Billing API, so you invoice the client directly and handle dunning yourself. They are bound to the store that installed them, and converting one into a public app later is a distribution rebuild — new client credentials, review, the mandatory compliance webhooks — not a config toggle. Our rule: internal automation gets an admin custom app, one client's product gets custom distribution, and anything you intend to sell to many merchants starts public on day one, while satisfying review is a checklist rather than a migration.

Model your data in metafields before you build a second database

New teams reflexively put custom product data in their own Postgres and sync it across. Then a Function needs it and cannot see it, because Functions read only what Shopify holds — there is no fetch, no escape hatch, no exception. Metafield definitions with typed validation, and metaobjects for repeatable structures like size charts, ingredient panels, or dealer locations, keep that data where the theme, the Storefront API, and Functions can all reach it, and where a merchant can edit it without waiting for your deploy. If it affects price, shipping, or display, Shopify is its source of truth.

Know the edges before they bite. Faceting a storefront collection on a metafield requires filters configured through Search & Discovery; it is not a free WHERE clause across your catalog. Long-text metafields have a size ceiling that shows up the first time a merchandiser pastes a full spec sheet. Keep a mirror in your own database for reporting and cross-system joins — just keep it the mirror, never the master.

You meet the rate limits during the first import

The Admin GraphQL API meters calculated query cost against a leaky bucket, not request count, which is why a loop that updates 40,000 variants stalls on day one of the migration while the identical code sailed through 200 test products. Bulk Operations exist for exactly this: upload JSONL, Shopify runs it asynchronously, you poll for the result file. Webhooks are at-least-once and arrive out of order, so every handler needs an idempotency key and every integration needs a nightly reconciliation job that re-reads state instead of trusting the event stream. Inventory is eventually consistent, and a checkout will happily oversell a variant your dashboard still shows in stock.

So, the short version. Presentation goes in the theme. State and logic go in an app. Decisions inside Shopify's own cart math go in a Function and may require Plus. Pixel-level control of checkout is not on the menu at any price. Sort the requirements that way and the estimate stops being a guess. Skip it and you pay for a build that discovers the fence in month two, with the client watching.

Written by Duskel

A software studio that ships and maintains its own products — KeepChats, Gwora and MoveProof — and builds the same way for clients. Founded and led by codewithumar.

Talk to the studio →
RELATED READING
Product Engineering · 7 min read

How to tell a real Next.js development company from a React shop

Product Engineering · 6 min read

Hire a full stack AI developer before you hire an ML team

Product Engineering · 8 min read

The custom Shopify app you want is probably not a public app

PRODUCT ENGINEERING

Send us the requirement you're not sure Shopify can handle and we'll tell you which layer it lives in.

Send the problem. You get one fixed number and a plan back within a business day.

Duskel
Duskel
AI AUTOMATIONSOFTWARE

We build software worth keeping — for clients, and for ourselves.

Founded & led by codewithumar

© 2026 Duskel. All rights reserved.DUSKEL SMC-Private Limited · Incorporated 2021 · Lahore, PakistanBuilt to last, not to demo.