# Shopify (Developer Platform) — full corpus
# LLM Wiki
An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f).
You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions.
## How It Works
The system has three layers:
```
raw/ Sources you collect (articles, transcripts, notes, PDFs)
wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses)
CLAUDE.md Schema that tells the LLM how to structure everything
```
Three operations drive the workflow:
| Operation | Trigger | What happens |
|-----------|---------|--------------|
| **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log |
| **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights |
| **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest |
## Quick Start
1. **Clone this repo**
```bash
git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base
cd my-knowledge-base
```
2. **Customize CLAUDE.md** for your domain
- Update the Purpose section with your topic
- Replace the placeholder tagging taxonomy with your own categories
- Adjust confidence level descriptions if needed
- Everything else (workflows, page formats, linking rules) works as-is
3. **Drop sources into `raw/`**
- Text files, transcripts, articles, notes — any plain text
- These are immutable once added; the LLM never modifies them
4. **Tell the LLM to ingest**
```
ingest raw/my-first-source.txt
```
The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index.
5. **Ask questions**
```
What are the key differences between X and Y?
```
The LLM answers from the wiki, citing specific pages.
6. **Run health checks**
```
lint
```
The LLM audits the wiki and fixes issues.
## Directory Structure
```
.
├── CLAUDE.md # Schema — the LLM's instructions
├── raw/ # Your source documents (immutable)
└── wiki/
├── index.md # Master catalog of all pages
├── log.md # Append-only activity log
├── dashboard.md # Dataview dashboard (Obsidian)
├── analytics.md # Charts View analytics (Obsidian)
├── flashcards.md # Spaced repetition cards
├── summaries/ # One page per source document
├── concepts/ # Concept and framework pages
├── entities/ # People, tools, organizations, etc.
├── syntheses/ # Cross-cutting analyses and comparisons
├── journal/ # Research/session journal entries
│ └── template.md # Journal entry template
└── presentations/ # Marp slide decks
```
## Enhancements
This template includes several extras beyond the core wiki pattern:
### Dataview Dashboard (`wiki/dashboard.md`)
Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin.
### Charts View Analytics (`wiki/analytics.md`)
Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin.
### Mermaid Diagrams
Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub.
### Marp Slides (`wiki/presentations/`)
Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory.
### Research Journal (`wiki/journal/`)
Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries.
### Spaced Repetition (`wiki/flashcards.md`)
Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page.
### MCP Server
This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically.
## Customizing for Your Domain
The schema in `CLAUDE.md` is domain-agnostic. To adapt it:
1. **Purpose** — Describe your knowledge domain in one paragraph
2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`)
3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards
4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.)
5. **Journal template** — Customize `wiki/journal/template.md` for your workflow
Everything else — page format, linking conventions, workflows, rules — is universal and works across domains.
## Example Domains
This template works for any knowledge-intensive topic:
- **Research notes** — papers, experiments, methodologies
- **Book analysis** — themes, characters, author techniques
- **Competitive analysis** — companies, products, market trends
- **Course notes** — lectures, readings, key concepts
- **Personal development** — frameworks, habits, book summaries
- **Technical documentation** — APIs, architectures, design patterns
- **Hobby deep-dives** — any subject you want to master
## License
MIT
---
title: "Shopify (Developer Platform) Knowledge Base — Index"
type: index
updated: 2026-07-07
shopify_api_version: "2026-07"
---
# Shopify Developer Platform — Knowledge Base
For developers and agents building on Shopify (shopify.dev), not merchant
store operations. Covers the Admin and Storefront GraphQL APIs and their usage
rules, OAuth and access scopes, app development (extensions, App Bridge,
webhooks, billing), Shopify Functions, custom data (metafields/metaobjects),
Liquid, theme architecture, Hydrogen headless, and the Shopify CLI - with
verbatim endpoints, limits, and syntax (API version 2026-07).
Master catalog - every page appears here.
## Concepts
### APIs
- [[concepts/what-is-shopify-dev]] - the platform: API families, surfaces, tooling
- [[concepts/authentication-and-access]] - OAuth, access tokens, scopes
- [[concepts/admin-graphql-api]] - the Admin GraphQL API
- [[concepts/admin-rest-api]] - the legacy Admin REST API (deprecated path)
- [[concepts/storefront-api]] - the Storefront GraphQL API (buyer-facing)
- [[concepts/api-usage]] - rate limits, versioning, pagination, bulk operations
### App development
- [[concepts/building-apps]] - app types, scaffolding, the CLI, app config
- [[concepts/app-extensions]] - admin and checkout UI extensions, targets
- [[concepts/app-bridge]] - embedding apps in the admin (App Home)
- [[concepts/webhooks]] - webhook topics, subscriptions, HMAC verification
- [[concepts/billing]] - the app billing API and pricing models
- [[concepts/functions]] - Shopify Functions (WASM backend logic)
### Data & storefronts
- [[concepts/custom-data-and-metafields]] - metafields and metaobjects
- [[concepts/liquid]] - the Liquid template language
- [[concepts/themes-architecture]] - theme structure, sections, blocks, templates
- [[concepts/hydrogen-and-headless]] - Hydrogen, headless commerce, Oxygen
- [[concepts/shopify-cli]] - the Shopify CLI
## Syntheses
- [[syntheses/admin-vs-storefront-api]] - Admin API vs Storefront API: which to use
- [[syntheses/app-surface-picker]] - Functions vs UI extensions vs App Bridge vs webhooks
- [[syntheses/liquid-themes-vs-hydrogen]] - classic Liquid themes vs Hydrogen headless
## XL edition (Pro)
Deeper per-item reference is available to Pro subscribers under this wiki's XL
edition (not listed above): the complete Liquid reference (every object, filter,
and tag with properties/parameters/return types), the Admin GraphQL object &
mutation reference, and the full webhook-topic catalog — 40 pages. Subscribe at /pro.
## Statistics
- **Total pages**: 20
- **Concepts**: 17
- **Entities**: 0
- **Summaries**: 0
- **Syntheses**: 3
---
title: "GraphQL Admin API"
type: concept
tags: [admin-api, graphql, api, store-data, foundational]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-admin-graphql-md.md"]
confidence: high
---
## Definition
The GraphQL Admin API is Shopify's primary interface for building apps and integrations that "extend and enhance the Shopify admin." It gives programmatic read/write access to core store data -- products, customers, orders, inventory, and more -- through a single GraphQL endpoint. As of April 1, 2025 it is the required API for all new public apps (the [[concepts/admin-rest-api|REST Admin API]] is legacy). It is a GraphQL API, so clients request exactly the fields they need and receive predictable, typed responses.
## How It Works
**Endpoint.** GraphQL queries are executed by sending `POST` HTTP requests to a single versioned endpoint:
`https://{store_name}.myshopify.com/admin/api/2026-07/graphql.json`
**Authentication.** "All GraphQL Admin API requests require a valid Shopify access token." Include it as an `X-Shopify-Access-Token` header on all requests (client libraries do this for you). See [[concepts/authentication-and-access]].
**Queries and mutations.** Queries begin with one of the objects under the `QueryRoot` (the schema's entry point) and "are equivalent to making a `GET` request in REST." Mutations write data and should request `userErrors` for debugging. Example verbatim query (get the ID and title of the first three products):
```graphql
query getProducts {
products (first: 3) {
edges {
node {
id
title
}
}
}
}
```
**cURL example (verbatim):**
```bash
curl -X POST \
https://{shop}.myshopify.com/admin/api/2026-07/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {SHOPIFY_ACCESS_TOKEN}' \
-d '{
"query": "query { shop { name } }"
}'
```
**Client libraries.** Officially supported: React Router (`@shopify/shopify-app-react-router`, the recommended package), Node.js (`@shopify/shopify-api`), Ruby (`shopify_api` gem), cURL, and Direct API Access. Direct API Access lets you "make requests to the Admin API directly from your app using the standard web `fetch` API. Requests are automatically authenticated" -- enabled in App Home via TOML:
```toml
[access.admin]
embedded_app_direct_api_access = true
```
With Direct API Access you call `fetch('shopify:admin/api/2026-07/graphql.json', ...)`.
**Tooling.** Explore the schema with the GraphiQL Explorer / Shopify's GraphiQL app.
## Key Parameters
- **HTTP method:** `POST` only.
- **Endpoint pattern:** `https://{store_name}.myshopify.com/admin/api/{version}/graphql.json`.
- **Current version cited by the docs:** `2026-07` (see [[concepts/api-usage]] for versioning).
- **Auth header:** `X-Shopify-Access-Token`.
- **Entry point:** `QueryRoot` (queries); mutations return `userErrors`.
- **Rate limiting:** calculated query cost, measured in cost points; the response `extensions.cost` object reports `requestedQueryCost`, `actualQueryCost`, and `throttleStatus` (`maximumAvailable`, `currentlyAvailable`, `restoreRate`). See [[concepts/api-usage]].
## When To Use
- Building any new app or integration that reads or writes Shopify admin/store data -- this is the default choice.
- Managing products, collections, variants, customers, orders, inventory, discounts, metafields, and more from a backend.
- Any scenario where REST would previously have been used -- migrate to GraphQL (new public apps must).
- For very large datasets, use bulk operations rather than paginating single queries (see [[concepts/api-usage]]).
## Risks & Pitfalls
- **GraphQL returns `200 OK` on errors.** "GraphQL HTTP status codes are different from REST API status codes... the GraphQL API can return a `200 OK` response code in cases that would typically produce 4xx or 5xx errors in REST." Always inspect the `errors` object, not just the HTTP status.
- **Cost-based throttling.** Exceeding the rate limit returns a `THROTTLED` error code ("Similar to 429 Too Many Requests"). A single query may not exceed 1,000 cost points -- exceeding it returns `MAX_COST_EXCEEDED`.
- **Key error codes (in `extensions.code`):** `THROTTLED`, `ACCESS_DENIED` ("Similar to 401 Unauthorized"), `SHOP_INACTIVE`, `INTERNAL_SERVER_ERROR` (returned instead of 500 in most cases).
- **Scope errors.** Requests fail with `ACCESS_DENIED` when the app lacks the required access scope. Request only the scopes you need.
- **Rare 4xx/5xx codes** still occur (402 shop frozen, 403 fraudulent, 404 deleted resource, 423 locked) but most error conditions surface as a 200 with an `errors` payload.
## Related Concepts
- [[concepts/admin-rest-api]]
- [[concepts/storefront-api]]
- [[concepts/authentication-and-access]]
- [[concepts/api-usage]]
- [[concepts/what-is-shopify-dev]]
- [[syntheses/admin-vs-storefront-api]]
## Sources
- raw/web_community-admin-graphql-md.md (GraphQL Admin API reference, api_version 2026-07 -- https://shopify.dev/docs/api/admin-graphql/latest)
---
title: "REST Admin API (Legacy)"
type: concept
tags: [admin-api, rest, api, legacy, deprecation, store-data]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-admin-rest-md.md"]
confidence: high
---
## Definition
The REST Admin API is Shopify's older, resource-oriented HTTP interface for building "apps and integrations that extend and enhance the Shopify admin." It exposes store resources (products, customers, orders, and so on) as REST endpoints returning JSON. It is now a legacy API: "The REST Admin API is a legacy API as of October 1, 2024. Starting April 1, 2025, all new public apps must be built exclusively with the [GraphQL Admin API]." New work should use the [[concepts/admin-graphql-api|GraphQL Admin API]]; this page exists mainly to explain the deprecation status and to support maintenance of existing REST integrations.
## How It Works
**Endpoint pattern.** "All Admin REST API endpoints follow this pattern:"
`https://{store_name}.myshopify.com/admin/api/2026-07/{resource}.json`
Endpoints are "organized by resource type," and you use standard HTTP verbs -- `POST` (create), `GET` (retrieve), `PUT` (update), `DELETE` (delete). Example verbatim endpoints for the Product resource:
- `POST /admin/api/2026-07/products.json` -- create a new product.
- `GET /admin/api/2026-07/products/{product_id}.json` -- retrieve a single product.
- `PUT /admin/api/2026-07/products/{product_id}.json` -- update a product.
- `DELETE /admin/api/2026-07/products/{product_id}.json` -- delete a product.
**Authentication.** "All REST Admin API queries require a valid Shopify access token." Include it as an `X-Shopify-Access-Token` header on all queries. Example verbatim GET:
```bash
curl -X GET \ https://{shop}.myshopify.com/admin/api/2026-07/shop.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {password}'
```
**Client libraries.** Officially supported: cURL, Remix (`@shopify/shopify-app-remix`), Node.js (`@shopify/shopify-api`), and Ruby (`shopify_api` gem). "Some newer platform features may only be available in GraphQL."
**Versioning and pagination.** "The Admin API is versioned, with new releases four times per year." "All REST endpoints support cursor-based pagination." See [[concepts/api-usage]].
## Key Parameters
- **Endpoint pattern:** `https://{store_name}.myshopify.com/admin/api/{version}/{resource}.json`.
- **Version cited:** `2026-07`.
- **HTTP verbs:** `GET`, `POST`, `PUT`, `DELETE`.
- **Auth header:** `X-Shopify-Access-Token`.
- **Rate limit:** "a limit of 40 requests per app per store per minute," replenishing "at a rate of 2 requests per second." "The rate limit is increased by a factor of 10 for Shopify Plus stores."
- **Rate-limit headers:** all responses include `X-Shopify-Shop-Api-Call-Limit` (for example `40/40`); a `429` response includes a `Retry-After` header (seconds to wait, for example `2.0`).
- **Pagination:** cursor-based.
## When To Use
- **Prefer GraphQL for anything new.** Per Shopify, new public apps must use GraphQL; there is no valid reason to start a new integration on REST.
- Maintaining or debugging an existing REST integration that has not yet migrated.
- Accessing a resource whose migration path you are still mapping -- but note "some newer platform features may only be available in GraphQL," so REST cannot reach all functionality.
## Risks & Pitfalls
- **Legacy status and App Store block.** REST is legacy as of October 1, 2024; since April 1, 2025 all new public apps "must be built exclusively with the GraphQL Admin API." Building a new public app on REST will fail distribution requirements. Follow the migration guide (https://shopify.dev/docs/apps/build/graphql/migrate).
- **Feature gaps.** "Some newer platform features may only be available in GraphQL." REST will increasingly lag.
- **Hard request-rate ceiling.** Unlike GraphQL's cost-based model, REST enforces a fixed 40 requests/app/store/minute (x10 for Plus). "Past the limit, the API will return a `429 Too Many Requests` error"; respect the `Retry-After` header.
- **REST error semantics differ from GraphQL.** REST returns conventional HTTP status codes: `401 Unauthorized` (bad credentials), `402 Payment Required` (shop frozen), `403 Forbidden` (typically incorrect access scopes), `404 Not Found`, `422 Unprocessable Entity` (semantic errors / missing required fields), `429 Too Many Requests`, and `5xx`. This is the opposite of GraphQL, which returns `200 OK` with an `errors` body -- do not reuse REST error-handling assumptions when you migrate.
## Related Concepts
- [[concepts/admin-graphql-api]]
- [[concepts/authentication-and-access]]
- [[concepts/api-usage]]
- [[concepts/what-is-shopify-dev]]
- [[syntheses/admin-vs-storefront-api]]
## Sources
- raw/web_community-admin-rest-md.md (REST Admin API reference, api_version 2026-07 -- https://shopify.dev/docs/api/admin-rest)
---
title: "API Usage: Rate Limits, Versioning, Pagination, Bulk Operations"
type: concept
tags: [rate-limits, versioning, pagination, bulk-operations, api, foundational]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-shopify-api-limits.md", "raw/web_community-queries-md.md", "raw/web_community-admin-graphql-md.md", "raw/web_community-admin-rest-md.md", "raw/web_community-storefront-md.md"]
confidence: high
---
## Definition
"API usage" covers the cross-cutting rules that apply across every Shopify API: how requests are rate-limited, how APIs are versioned, how results are paginated, and how to fetch large datasets with bulk operations. These rules are independent of which API family you use, and getting them right is what keeps an integration stable at scale. This page collects the exact limits and formats.
## How It Works
**Rate limiting.** "All Shopify APIs use a leaky bucket algorithm to manage requests." Each app has a bucket; each request adds to it; capacity restores over time; a full bucket returns a throttle error. Different APIs meter differently:
- **GraphQL APIs (Admin, Payments Apps, Customer Account)** use a *calculated query cost* method. "Every field in the schema has an integer cost value assigned to it. The cost of a query is the maximum of possible fields selected." Default costs: Scalar 0, Enum 0, Object 1, Interface/Union = maximum of possible selections, Connection = sized by `first`/`last` arguments, Mutation 10.
- **REST Admin API** uses a fixed request bucket: 40 requests/app/store/minute, restoring at 2 requests/second (x10 for Shopify Plus).
- **Storefront API** has "None" -- real buyer traffic is not subject to a fixed request-per-minute limit; only automated/bot traffic is limited.
**Requested vs actual cost.** Shopify calculates cost "both before and after execution." The requested cost must fit the bucket before execution; afterward "the bucket is refunded the difference between the requested cost and the actual cost."
**Versioning.** All APIs are "versioned, with new releases four times per year" (quarterly). Versions use a `YYYY-MM` date format (for example `2026-07`); `latest` is an alias for the newest stable version. Always specify a supported version in the request URL to keep an app stable.
**Pagination.** REST endpoints "support cursor-based pagination"; GraphQL uses connection/edge cursors (`first`/`last`). "Shopify limits pagination of arrays of objects to 25,000 objects." The limit is also enforced on count queries: "Counts are accurate up to 25,000 items. For arrays with more items, 25,001 is returned as the count." Add filters to narrow results below the limit.
**Bulk operations.** For large datasets, "you should use bulk operations instead of single queries. Bulk operations are designed for handling large amounts of data, and they don't have the max cost limits or rate limits that single queries have." Submit with `bulkOperationRunQuery` (or `bulkOperationRunMutation`); Shopify runs it asynchronously and delivers results as a JSONL file at a URL. Wait for completion by subscribing to the `bulk_operations/finish` webhook topic (recommended) or by polling status. Bulk operations are "only available through the GraphQL Admin API. You can't perform bulk operations with the Storefront API."
## Key Parameters
**GraphQL Admin API rate limits (verbatim, calculated query cost):**
| Plan tier | Limit |
| - | - |
| Standard | 100 points/second |
| Advanced Shopify | 200 points/second |
| Shopify Plus | 1000 points/second |
| Shopify for enterprise (Commerce Components) | 2000 points/second |
- **Single query limit:** "A single query may not exceed a cost of 1,000 points, regardless of plan limits" (enforced pre-execution on requested cost; exceeding returns `MAX_COST_EXCEEDED`).
- **REST Admin API:** 40 requests/app/store/minute; 2 requests/second restore; x10 for Plus; `429 Too Many Requests` past the limit; `X-Shopify-Shop-Api-Call-Limit` header (for example `40/40`) and `Retry-After` on 429.
- **Storefront API:** no fixed rate limit for real buyers; tokenless query complexity limit 1,000; `430 Shopify Security Rejection` for malicious traffic; sign bots with Web Bot Auth.
- **Input array limit:** "Input arguments that accept an array have a maximum size of 250 for all APIs."
- **Pagination limit:** 25,000 objects (count returns `25001` beyond that).
- **Bulk concurrency:** "In API versions `2026-01` and higher apps can run up to five bulk query operations at a time per shop. In API versions prior to `2026-01`, apps are limited to running a single bulk operation at a time per shop." A bulk operation "has to complete within 10 days" or it is marked `failed`.
- **Resource throttle:** once a store has 50,000 product variants, "no more than 1,000 new variants can be created per day" (`productCreate`, `productUpdate`, `productVariantCreate`); does not apply to Shopify Plus.
- **Version format:** `YYYY-MM` (for example `2026-07`), released quarterly.
**GraphQL cost response (verbatim shape):**
```json
"extensions": {
"cost": {
"requestedQueryCost": 101,
"actualQueryCost": 46,
"throttleStatus": {
"maximumAvailable": 1000,
"currentlyAvailable": 954,
"restoreRate": 50
}
}
}
```
Add the header `Shopify-GraphQL-Cost-Debug=1` for a per-field cost breakdown.
## When To Use
- Designing retry/backoff logic -> read the throttle status and respect `Retry-After`; recommended backoff is one second.
- Choosing a version -> pin a supported `YYYY-MM` version; plan quarterly upgrades.
- Fetching more than a page or two of data -> paginate with cursors, and switch to bulk operations well before the 25,000-object pagination ceiling.
- Fetching very large datasets or exports -> use `bulkOperationRunQuery` on the GraphQL Admin API.
## Risks & Pitfalls
- **Assuming a request-count limit on GraphQL.** GraphQL is cost-based, not request-count-based; a few expensive queries can throttle you while many cheap ones do not. Monitor `extensions.cost`.
- **Single-query cost ceiling.** Any single query over 1,000 points is rejected before execution -- split it or use bulk operations.
- **Pagination ceiling surprises.** You cannot page past 25,000 items, and counts saturate at `25001`; add filters or use bulk operations.
- **Bulk concurrency depends on version.** Only `2026-01`+ allows five concurrent bulk operations; older versions allow one -- and bulk is Admin-only (not Storefront).
- **Version drift.** Not pinning a supported version, or letting a pinned version age out of support, breaks apps; upgrade on Shopify's quarterly cadence.
- **Ignoring throttle errors.** "If you ignore these errors and keep trying to make requests, then your app won't be able to gracefully recover." Stop and back off.
- **Missing Buyer IP / unsigned bots on Storefront** invite strict rate limits and `430` rejections.
## Related Concepts
- [[concepts/admin-graphql-api]]
- [[concepts/admin-rest-api]]
- [[concepts/storefront-api]]
- [[concepts/authentication-and-access]]
- [[concepts/webhooks]]
- [[concepts/what-is-shopify-dev]]
## Sources
- raw/web_community-shopify-api-limits.md (Shopify API limits -- https://shopify.dev/docs/api/usage/rate-limits)
- raw/web_community-queries-md.md (Perform bulk operations with the GraphQL Admin API -- https://shopify.dev/docs/api/usage/bulk-operations/queries)
- raw/web_community-admin-graphql-md.md (versioning, cost response -- https://shopify.dev/docs/api/admin-graphql/latest)
- raw/web_community-admin-rest-md.md (REST rate limits, pagination -- https://shopify.dev/docs/api/admin-rest)
- raw/web_community-storefront-md.md (Storefront rate limits -- https://shopify.dev/docs/api/storefront/latest)
---
title: "Shopify App Bridge and App Home"
type: concept
tags: [app-bridge, app-home, embedded-apps, polaris, session-token]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-app-bridge-md.md", "raw/web_community-app-bridge-library-md.md"]
source_url: "https://shopify.dev/docs/api/app-home"
confidence: high
---
## Definition
App Home is the dedicated area in the Shopify admin where your app renders its
landing page and UI, and the main surface through which merchants use your app.
Your app communicates with other parts of the Shopify admin using a JavaScript SDK
called App Bridge, and renders its UI inside an iframe using web components. There
are two ways to build for App Home: iframe-based apps (covered here) and App Home
UI extensions.
## How It Works
The App Home area is implemented as an iframe. To interact with admin components
outside this iframe, apps use the App Bridge JavaScript SDK. You use App Bridge
APIs to communicate with the admin, and App Bridge web components to add UI (title
bars, navigation menus) to the admin outside your app's iframe.
To start, scaffold an app with [[concepts/shopify-cli|Shopify CLI]] and select
**Build a React Router app**. The command creates a framework that includes all of
the App Bridge and Polaris libraries you need:
```terminal
cd my-app
shopify app init
```
Apps scaffolded with Shopify CLI already include the App Bridge script, so you
don't need to add it manually. When the App Bridge script is included, you don't
need to set up or configure any additional authentication to use the APIs: your app
runs inside an authenticated session in the admin, so you don't manage tokens or
headers yourself.
The App Bridge APIs are exposed through the `shopify` global variable. They let you
read information from the admin, launch workflows (creating products, editing
orders), and provide feedback through toasts and modals.
## Key Parameters
**Loading the libraries (CDN + types).** Loading App Bridge from
`cdn.shopify.com/shopifycloud/app-bridge.js` installs the latest version of the
library; for TypeScript, add `@shopify/app-bridge-types@latest` to `package.json`.
Polaris web components load from `cdn.shopify.com/shopifycloud/polaris.js` (latest
version); pair with `@shopify/polaris-types@latest`. Polaris components are built on
the Web Components standard, so they work like native HTML elements in any framework
or vanilla JavaScript.
**Rendering a page** with Polaris web components:
```jsx
export default function App() {
return (
Welcome to your Shopify app! Start building the main interface here.
);
}
```
**Title bar and navigation menu** outside the iframe use App Bridge web components
from `@shopify/app-bridge-react`:
```jsx
import {TitleBar, NavMenu} from '@shopify/app-bridge-react';
export default function App() {
return (
<>
HomeProductsSettings
>
);
}
```
**Authenticating with your backend.** Retrieve a session token with
`shopify.idToken()` and send it as a bearer token:
```jsx
export default function App() {
const syncProducts = async () => {
const token = await shopify.idToken();
await fetch('/api/sync-products', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
});
};
return (
);
}
```
**Direct API access.** Your app can query the
[[concepts/admin-graphql-api|Admin GraphQL API]] directly from front-end code using
`fetch()`. App Bridge automatically authenticates these requests; use the
`shopify:admin/api/graphql.json` URL:
```jsx
async function getProducts() {
const response = await fetch('shopify:admin/api/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query {
products(first: 10) {
edges {
node {
id
title
}
}
}
}
`,
}),
});
const { data } = await response.json();
return data.products.edges;
}
```
**Configuration.** App configuration lives in `shopify.app.toml`. To enable direct
API access, set `embedded_app_direct_api_access = true` and control token mode with
`direct_api_mode` (`online` = current user session; `offline` = persists for
background jobs). You must declare the access scopes your app needs; merchants
approve them on install.
```toml
# Add these settings to shopify.app.toml to control API access and scopes
[access_scopes]
scopes = "read_products,write_products"
[access.admin]
embedded_app_direct_api_access = true
direct_api_mode = "online"
```
## When To Use
Use App Bridge for embedded, iframe-based apps that render in the admin and need to
reach admin surfaces outside their iframe (navigation, title bars, resource
workflows, toasts, modals) or to call the Admin GraphQL API directly. For simple
extension-only apps with no backend, prefer an App Home UI extension instead. See
[[concepts/building-apps|Building apps]] for scaffolding and
[[syntheses/app-surface-picker|the app surface picker]].
## Risks & Pitfalls
- App Home apps run inside an iframe; UI added outside the iframe must go through
App Bridge web components.
- Request only the access scopes your app actually needs.
- Loading libraries from the CDN pulls the latest version; keep the paired
`@latest` type packages in step to avoid type drift.
## Related Concepts
- [[concepts/building-apps|Building apps]]
- [[concepts/app-extensions|App extensions]]
- [[concepts/admin-graphql-api|Admin GraphQL API]]
- [[concepts/authentication-and-access|Authentication and access]]
- [[concepts/shopify-cli|Shopify CLI]]
## Sources
- raw/web_community-app-bridge-md.md
- raw/web_community-app-bridge-library-md.md
---
title: "App Extensions"
type: concept
tags: [app-extensions, admin-ui-extensions, checkout-ui-extensions, targets, toml]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-app-extensions-md.md", "raw/web_community-admin-extensions-md.md", "raw/web_community-checkout-ui-extensions-md.md"]
source_url: "https://shopify.dev/docs/apps/build/app-extensions"
confidence: high
---
## Definition
An app extension adds your app's functionality to Shopify user interfaces where
and when users need it. An extension isn't an app; it's a mechanism that lets an
app add features to defined parts of several Shopify UIs (admin, checkout, POS, and
more). Apps that use extensions must adhere to the same authentication requirements
and rate limits as apps that don't.
## How It Works
Without an app extension, users interact directly with your app. With an app
extension, users interact with Shopify, and Shopify relays information to your app
that is surfaced back through your extension. You create extensions with
[[concepts/shopify-cli|Shopify CLI]] and the `app generate extension` command:
```terminal
cd my-app
shopify app generate extension
```
When you generate an extension, a TOML configuration file named
`shopify.extension.toml` is created in the extension's directory under
`extensions/`. Your app configuration and all extensions are versioned together as
a single app version; running `shopify app deploy` creates and releases a version.
UI extensions are made of three interconnected parts: **targets** (where the
extension appears), **target APIs** (what it can access/do), and **web components**
(the interface elements). When an extension runs, Shopify provides a `shopify`
global object; most target APIs are properties on it (for example `shopify.data`,
`shopify.query()`, `shopify.navigation.navigate()`). Web components are native UI
elements that follow Shopify's Polaris design system and are built with remote-dom.
### Admin UI extensions
Admin UI extensions integrate into the Shopify admin (custom content blocks on
product/order pages, action modals from context menus, settings UIs for Functions).
They require a TOML config and Preact-based TSX/JSX files. There are six target
types:
- **Action** - menu items in the **More actions** menu on detail/index pages;
renders in a modal. Has Render and Should render varieties.
- **Selection action** - **More actions** items on index pages when multiple
resources are selected (bulk operations). Render and Should render varieties.
- **Block** - inline cards on resource pages; merchants must add and pin them.
- **Configuration** - configuration interfaces (product/variant configuration for
bundles, and Function settings for discount, validation, and order-routing
functions).
- **Print action** - items in the **Print** menu on order and product pages.
- **Runnable** - executes code and returns data to Shopify without rendering UI
(for example Sidekick and customer segment templates).
A sample admin `shopify.extension.toml`:
```toml
api_version = "2026-04"
[[extensions]]
type = "ui_extension"
name = "My Admin UI extension"
handle = "my-admin-ui-extension"
uid = "f62f100d-15e6-9866-eda9-23f99de4b5d26e347042"
description = "Custom product details extension"
[[extensions.targeting]]
target = "admin.product-details.block.render"
module = "./src/ProductBlock.tsx"
[[extensions.targeting]]
target = "admin.product-details.action.render"
module = "./src/ProductAction.tsx"
```
Admin extensions can query Shopify data directly (Direct API access) via
`shopify.query()` or `fetch('shopify:admin/api/graphql.json', ...)`; these calls are
automatically authenticated. Direct API uses online access mode by default; set
`direct_api_mode = "offline"` to use offline mode. You must declare all required
access scopes in the app TOML.
### Checkout UI extensions
Checkout UI extensions add custom UI and logic into any step of the Shopify
checkout, including the Thank you page. Scaffold with a template:
```bash
cd my-app
shopify app generate extension --template checkout_ui
```
Checkout targets come in three types: **Block** (flexible placement merchants
position via the checkout and accounts editor), **Runnable** (data/functionality
without UI), and **Static** (fixed locations that render automatically). A sample
`shopify.extension.toml`:
```toml
api_version = "2026-07"
[[extensions]]
type = "ui_extension"
name = "My checkout UI extension"
handle = "my-checkout-extension"
uid = "fddfc370-27c7-c30f-4ee0-a927194e2accadefd40c"
[[extensions.targeting]]
target = "purchase.checkout.block.render"
module = "./src/Checkout.tsx"
[[extensions.targeting]]
target = "purchase.thank-you.block.render"
module = "./src/ThankYou.tsx"
```
Checkout extensions can apply changes with methods like `applyAttributeChange` (set
a cart attribute) and `applyMetafieldChange` (write a cart metafield); batch
multiple changes with `Promise.all`. Optional TOML sections include
`[extensions.capabilities]` (`api_access`, `network_access`, `collect_buyer_consent`,
`block_progress`), `[[extensions.metafields]]`, and `[extensions.settings]`.
## Key Parameters
Shared `[[extensions]]` properties: `type` (`ui_extension`), `name` (5-30 chars,
merchant/customer-facing, translatable with `t:`), `handle` (immutable after
draft/deploy; `a-z A-Z 0-9 -`), `uid` (unique app-scoped id), and optional
`description`. `[[extensions.targeting]]` requires `target` and `module`.
## When To Use
Use app extensions for quick, frequent actions surfaced inside Shopify. Choose
admin extensions for merchant workflows on admin resource pages; choose checkout UI
extensions to customize checkout (information, shipping, and payment steps are
Shopify Plus only). Consult the list of app extensions to pick a type. See
[[syntheses/app-surface-picker|the app surface picker]].
## Risks & Pitfalls
- A compiled UI extension bundle can't exceed 64 KB (compressed); Shopify enforces
this at deployment. `shopify app build` (CLI 3.92.0+) emits a `.metafile.json`
per extension for bundle analysis.
- Some extension types must be reviewed and approved before an app version can be
released.
- Checkout extensions run in an isolated Web Worker sandbox with no access to
`window`/DOM or payment data; rate limits may apply to changes.
- Extension-only apps can only be installed with custom distribution.
## Related Concepts
- [[concepts/building-apps|Building apps]]
- [[concepts/app-bridge|App Bridge]]
- [[concepts/functions|Shopify Functions]]
- [[concepts/custom-data-and-metafields|Custom data and metafields]]
- [[concepts/shopify-cli|Shopify CLI]]
## Sources
- raw/web_community-app-extensions-md.md
- raw/web_community-admin-extensions-md.md
- raw/web_community-checkout-ui-extensions-md.md
---
title: "Authentication and Access (OAuth, Tokens, Scopes)"
type: concept
tags: [authentication, oauth, access-tokens, access-scopes, security, foundational]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-authentication-md.md", "raw/web_community-authentication-authorization-md.md", "raw/web_community-access-tokens-md.md", "raw/web_community-access-scopes-md.md"]
confidence: high
---
## Definition
Every Shopify API request must be authenticated, and every app must be authorized to access store data. Shopify distinguishes the two precisely: "Authentication is the process of verifying the identity of the user or the app... all apps connecting with Shopify APIs must authenticate when making API requests. Authorization is the process of giving permissions to apps. When an app user installs a Shopify app they authorize the app, enabling the app to acquire an access token." Authorization is built on OAuth 2.0, "the industry-standard protocol for authorizing or giving permissions to apps." Access scopes (for example `read_products`, `write_orders`) declare exactly which store data an app may touch.
## How It Works
**Authentication of incoming requests.** Apps rendered in the Shopify admin authenticate incoming requests with session tokens (acquired via [[concepts/app-bridge|App Bridge]]). Standalone apps must implement their own authentication for incoming requests.
**Authorization / token acquisition.** "The Shopify platform provides two ways for apps to acquire an access token: token exchange and authorization code grant. Apps rendered in the Shopify admin should use token exchange, while standalone apps need to use authorization code grant."
- **Token exchange (recommended for embedded apps):** OAuth 2.0 token exchange (RFC 8693) "allows apps to exchange a session token for an access token." The session token is only available for apps rendered in the Shopify admin.
- **Authorization code grant (standalone apps):** the classic OAuth flow -- user requests install, app redirects to Shopify's grant screen requesting scopes, user consents, app receives an authorization grant, exchanges it for an access token, then uses that token on API requests.
- **Client credentials grant:** for apps built "for your own organization" that "don't require user interaction."
- **Shopify managed installation (recommended):** configure required scopes via the Shopify CLI TOML config so "Shopify [manages] the installation process for you," avoiding redirects and page flickers. Without CLI config, the app installs via the authorization code grant flow, "a degraded user experience."
**Admin API token use.** Include the token as an `X-Shopify-Access-Token` header on Admin API requests. Tokens are either online (tied to a user) or offline (long-lived, app-level) -- Shopify's official libraries handle token handling for you.
**Storefront API tokens.** The [[concepts/storefront-api|Storefront API]] supports tokenless and token-based access. Two token-based types:
- **Public access tokens:** for client-side contexts (browser, mobile app). Created via the GraphQL Admin API `storefrontAccessTokenCreate` mutation. Send as the `X-Shopify-Storefront-Access-Token` header. "Apps can have a maximum of 100 active storefront access tokens per shop."
- **Private access tokens:** for server-side contexts; "should be treated as secret and not used on the client-side." Send as the `Shopify-Storefront-Private-Token` header. When serving buyer traffic, also include the `Shopify-Storefront-Buyer-IP` (case-sensitive) header with the buyer's IP.
## Key Parameters
**Token acquisition flows by app type (verbatim):**
| Type of app | Installation flows | Token acquisition flows |
| - | - | - |
| App rendered in the Shopify admin | Shopify managed installation (recommended); Installation during authorization code grant | Token exchange (recommended); Authorization code grant |
| Standalone app | Shopify managed installation (recommended); Installation during authorization code grant | Authorization code grant |
| Admin-created custom app | Installed upon generation in the Shopify admin | Generate in the Shopify admin |
**Scope types (verbatim):**
- **Authenticated** scopes -- control access to the GraphQL Admin API, Web Pixel API, and Payments Apps API ("on behalf of a user"). Examples: `read_products`,`write_products`; `read_orders`,`write_orders`; `read_customers`,`write_customers`; `read_inventory`,`write_inventory`; `read_discounts`,`write_discounts`; `read_content`,`write_content`; `read_themes`,`write_themes`; `read_metaobjects`,`write_metaobjects`. `read_all_orders` (permissions required) exposes orders beyond "the default window of orders created within the last 60 days." `read_users` is `StaffMember` (Shopify Plus).
- **Unauthenticated** scopes -- read-only Storefront API access ("on behalf of a customer"): `unauthenticated_read_product_listings`, `unauthenticated_read_product_inventory`, `unauthenticated_read_product_tags`, `unauthenticated_read_content`, `unauthenticated_read_metaobjects`, `unauthenticated_read_selling_plans`, `unauthenticated_read_customers`,`unauthenticated_write_customers`, `unauthenticated_read_checkouts`,`unauthenticated_write_checkouts`.
- **Customer** scopes -- Customer Account API: `customer_read_customers`,`customer_write_customers`; `customer_read_orders`,`customer_write_orders`; `customer_read_companies`,`customer_write_companies`.
Check granted scopes with the `appInstallation` query in the GraphQL Admin API.
## When To Use
- Building a new embedded (admin-rendered) app -> use session tokens + token exchange + Shopify managed installation.
- Building a standalone app -> use authorization code grant.
- Building for your own org, no user interaction -> client credentials grant.
- Querying the Storefront API client-side -> public access token; server-side -> private access token.
- Deciding which scopes to request -> pick the minimum authenticated/unauthenticated/customer scopes for the data your app needs.
## Risks & Pitfalls
- **Never expose private tokens client-side.** "Unlike public access tokens, private access tokens should be treated as secret and not used on the client-side."
- **Missing Buyer-IP header degrades service.** Omitting `Shopify-Storefront-Buyer-IP` on buyer-driven server requests "can result in sub-optimal user experiences, including throttled API requests, limited Bot Protection, and unauthenticated flows at checkout."
- **Over-requesting scopes.** "Apps should request only the minimum amount of data that's necessary... Shopify restricts access to scopes for apps that don't require legitimate use of the associated data."
- **Permissions-gated scopes.** `read_all_orders`, subscription scopes, and protected customer data require explicit Partner Dashboard approval; adding them alone will not return data on non-development stores.
- **Legacy app types.** "Only public or custom apps are granted access scopes. Legacy app types, such as private or unpublished, won't be granted new access scopes."
- **Not using CLI config.** Skipping CLI scope configuration forces the authorization code grant install flow, "a degraded user experience."
## Related Concepts
- [[concepts/what-is-shopify-dev]]
- [[concepts/admin-graphql-api]]
- [[concepts/storefront-api]]
- [[concepts/app-bridge]]
- [[concepts/building-apps]]
- [[concepts/shopify-cli]]
## Sources
- raw/web_community-authentication-md.md (Shopify API authentication -- https://shopify.dev/docs/api/usage/authentication)
- raw/web_community-authentication-authorization-md.md (Authentication and authorization -- https://shopify.dev/docs/apps/build/authentication-authorization)
- raw/web_community-access-tokens-md.md (About token acquisition)
- raw/web_community-access-scopes-md.md (Shopify API access scopes -- https://shopify.dev/docs/api/usage/access-scopes)
---
title: "App Billing"
type: concept
tags: [billing, monetization, app-pricing, subscriptions, usage-charges]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-billing-md.md"]
source_url: "https://shopify.dev/docs/apps/launch/billing"
confidence: high
---
## Definition
Shopify App Pricing enables you to monetize apps distributed through the Shopify
App Store. It creates a predictable, trustworthy, and standardized billing
experience for merchants, and an easy way to set up pricing for public app
developers. All apps published on the Shopify App Store are required to use a
Shopify-provided billing solution and to adhere to the Shopify Partner Program
Agreement.
## How It Works
**Shopify App Pricing** is the default and recommended approach for all apps
published on the App Store. You define plans in the app submission form and let
Shopify host your plan-selection page and automate billing, trials, proration,
upgrades, and downgrades. The flow is: the merchant initiates an upgrade, the app
redirects to the Shopify admin, Shopify processes the charge and redirects to the
welcome link, then the app verifies the subscription and optionally sends usage
charges.
Shopify App Pricing supports recurring and usage charges. It is available for free,
monthly and annual recurring, and various usage-based plan types. You send billable
usage events via the App Events API.
**Manual Pricing (Legacy)** is still supported but is the legacy method. With manual
pricing, you build your own billing logic and pricing page using the Billing API to
create recurring, usage, or one-time charges. It remains available for apps with
specific requirements not yet covered by Shopify App Pricing, and for existing
developers already using it.
## Key Parameters
Benefits Shopify App Pricing provides:
- **Simplified payment process** - charges are added directly to the merchant's
Shopify invoice.
- **Increased conversion rates** - higher free-to-paid conversion because of higher
trust and charges originating directly from Shopify.
- **Revenue sharing** - you automatically receive a share of the revenue Shopify
collects.
- **Chargeback handling** - Shopify handles all chargeback-related processes.
- **Flexible pricing models** - a wide range of common pricing models.
**Charge types available through the Billing API (manual pricing):** recurring,
usage, and one-time charges.
**Supported currencies.** You can match app charges to a merchant's local billing
currency if they use one of the supported currencies. Retrieve the merchant's local
billing currency with the GraphQL Admin API's `shopBillingPreferences` query,
passing the currency value as input.
## When To Use
Use **Shopify App Pricing** for essentially all new App Store apps: it is the
default, required, recommended approach and gives you Shopify-hosted plan selection
plus automated trials, proration, upgrades, and downgrades. Use **Manual Pricing
(Billing API)** only when your app has specific requirements not yet covered by
Shopify App Pricing, or when you are an existing developer already on it.
Best practices when designing a pricing model:
- **Provide simple and intuitive pricing** - makes the model easier to understand
and encourages adoption. Example: for a single feature set, consider time-based
subscriptions at 30 or 365-day intervals.
- **Limit the number of plans** - makes plans easier to compare. Example: a basic
plan and a pro plan, using usage-based pricing to differentiate where appropriate.
- **Offer free trials** - encourages merchants and Partners to try before they pay.
Example: align with Shopify's free trial or $1 plan.
- **Create charges in the merchant's local billing currency** - helps merchants
budget app spend. Example: bill a merchant in India in INR, and one in Canada in
CAD.
## Risks & Pitfalls
- App Store apps must use a Shopify-provided billing solution; building custom
external billing for a published app violates the Partner Program Agreement.
- Manual Pricing is legacy; new apps should default to Shopify App Pricing unless a
specific requirement forces otherwise.
- Local-currency billing only works for the set of supported currencies; check the
merchant's `shopBillingPreferences` before assuming a currency is available.
## Related Concepts
- [[concepts/building-apps|Building apps]]
- [[concepts/admin-graphql-api|Admin GraphQL API]]
- [[concepts/webhooks|Webhooks]]
## Sources
- raw/web_community-billing-md.md
---
title: "Building Shopify Apps"
type: concept
tags: [apps, cli, scaffolding, app-config, embedded-apps]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-build-md.md", "raw/web_community-scaffold-app-md.md"]
source_url: "https://shopify.dev/docs/apps/build/scaffold-app"
confidence: high
---
## Definition
A Shopify app extends the Shopify commerce platform across surfaces (admin pages,
checkout, storefront themes, POS, automation), APIs, and backend logic to solve
merchant problems. You build apps with APIs, web components, and backend logic.
This page covers how apps are typed, scaffolded with the CLI, and configured.
## How It Works
There are three main starting points, chosen by what the app needs:
- **React Router app (recommended for most apps)** - an embedded app that users
access from the Shopify admin. Scaffolded from the
[React Router template](https://github.com/Shopify/shopify-app-template-react-router).
This is the recommended path for most apps.
- **Extension-only app** - a simple custom-distribution app that doesn't need
server-side logic. Built with the extension-only template plus an App Home UI
extension. Extension-only apps can only be installed with custom distribution.
- **Simple integration (no embedded UI)** - if you're connecting an existing
system to Shopify and only need API credentials, create an app in the Dev
Dashboard instead of scaffolding.
Scaffolding uses [[concepts/shopify-cli|Shopify CLI]]. Navigate to the directory
where you want the app (it is created in a new subdirectory), then run:
```terminal
shopify app init
```
When prompted, enter a name and select **Build a React Router app**. A new app is
created and Shopify CLI is installed along with all the dependencies you need to
build Shopify apps.
Start a local development server from inside the app directory:
```terminal
cd my-new-app
```
```terminal
shopify app dev
```
Shopify CLI uses Cloudflare to create a tunnel so your app can be accessed over an
HTTPS URL. Running `dev` also:
- Guides you through logging into your developer account (a Partner account or a
merchant account with appropriate permissions).
- Creates an app in the Dev Dashboard and connects your local code to it.
- Creates your Prisma SQLite database.
- Creates a tunnel between your local machine and the dev store.
With the server running, press `p` to open your app's preview URL, then click
**Install app** to install it on the dev store.
## Key Parameters
**App configuration** lives in `shopify.app.toml`, created for you when you
scaffold. It controls how your app authenticates, what data it can access, and how
it integrates with the admin. A minimal access block looks like:
```toml
# Add these settings to shopify.app.toml to control API access and scopes
[access_scopes]
scopes = "read_products,write_products"
[access.admin]
embedded_app_direct_api_access = true
direct_api_mode = "online"
```
- `[access_scopes] scopes` declares what data your app can read/write via the
Admin GraphQL API. Merchants approve these on install; request only what you need.
- `embedded_app_direct_api_access` enables direct calls to the Admin GraphQL API
from front-end code.
- `direct_api_mode` selects `online` (tied to the current user session) or
`offline` (persists, for background jobs) tokens.
**Project structure**: app extensions live in the `extensions/` directory, each
with its own `shopify.extension.toml`. Your app configuration and all extensions
are versioned together as a single app version.
**Deploy** creates and releases an app version:
```terminal
shopify app deploy
```
Deploy your backend to a hosting service (for example Google Cloud Run, Fly.io, or
Render) first; the CLI `deploy` command then syncs your app configuration and
extensions to Shopify so merchants can install it.
## When To Use
- Use the React Router template for embedded apps that need server-side logic and
an admin UI built with [[concepts/app-bridge|App Bridge]] and Polaris.
- Use the extension-only template when the whole app is made of
[[concepts/app-extensions|extensions]] and needs no developer-hosted backend.
- Use the Dev Dashboard for a pure API integration with no UI. See
[[syntheses/app-surface-picker|the app surface picker]] to choose a surface.
All UI surfaces share Polaris, Shopify's unified design system. A single app can
extend multiple surfaces: App Home, admin, checkout, customer accounts, Flow,
online store, POS, and Sidekick. Backend building blocks include GraphQL,
[[concepts/app-extensions|extensions]], [[concepts/functions|Shopify Functions]],
ShopifyQL, Events, [[concepts/webhooks|webhooks]], and metafields.
## Risks & Pitfalls
- To use a dev store with Shopify CLI you must be the store owner or have a staff
account on the store. Creating a dev store assigns you as owner; other staff must
be added.
- You need to be a user with app development permissions and have created a dev
store before scaffolding.
- Use the latest version of Shopify CLI and of Chrome or Firefox.
- Follow Shopify's best-practice guidelines (performance, accessibility, security,
compliance) to meet App Store requirements.
## Related Concepts
- [[concepts/shopify-cli|Shopify CLI]]
- [[concepts/app-bridge|App Bridge]]
- [[concepts/app-extensions|App extensions]]
- [[concepts/billing|Billing]]
- [[concepts/authentication-and-access|Authentication and access]]
## Sources
- raw/web_community-build-md.md
- raw/web_community-scaffold-app-md.md
---
title: "Custom Data: Metafields and Metaobjects"
type: concept
tags: [custom-data, metafields, metaobjects, data-modeling, graphql]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-custom-data-md.md", "raw/web_community-metafields-md.md"]
confidence: high
---
# Custom Data: Metafields and Metaobjects
## Definition
Shopify includes built-in data models like products, customers, and orders. **Metafields** extend these models by letting you add custom data to any Shopify resource (a `MetafieldOwnerType` such as `PRODUCT`, `CUSTOMER`, `ORDER`). Use them for warranty info, customer lifetime value, fulfillment notes, related-product links, or to trigger Shopify Flow automations. Metafields add individual custom fields to specific resources; when you need standalone objects with multiple related fields, use **metaobjects** instead.
## How It Works
A metafield is a key-value pair with three components:
* **Identifier**: a combination of namespace and key (for example, `custom.warranty_info`). Namespaces are logical containers that provide organization, prevent naming conflicts, and establish ownership.
* **Value**: the data being stored.
* **Type**: defines the kind of value (text, number, date, reference) and how it is interpreted.
### Metafield definitions
Before creating a metafield you create a **metafield definition**. Definitions establish data schemas that enable type validation, Shopify admin integration, query filtering, access control, and performance optimization. Shopify also provides pre-built "standard" definitions for common cases (ISBN numbers, product ingredients, care instructions) that improve interoperability.
### Ownership models
Ownership determines access and control:
| Ownership Type | Purpose | Namespace |
| - | - | - |
| App-owned | App-managed data for internal logic, configuration, and workflows | Reserved namespace `$app` (GraphQL) or `app` (TOML) |
| Merchant-owned | Merchant-managed data shared across all apps | Any non-reserved namespace, such as `custom` |
Additional types: **Shopify-reserved** (controlled by Shopify, typically prefixed `shopify--`, usually merchant-owned) and **App-data** (app-owned, tied to the app installation, hidden from the admin).
## Key Parameters
### App-owned metafields (TOML + GraphQL)
Define app-owned metafields in `shopify.app.toml` using the `app` reserved namespace, then deploy:
```toml
[product.metafields.app.internal_sku]
name = "Internal SKU"
description = "Internal inventory tracking code"
type = "single_line_text_field"
```
```bash
shopify app deploy
```
Then set the value via the GraphQL Admin API (POST `https://{shop}.myshopify.com/api/{api_version}/graphql.json`), using the `$app` namespace:
```graphql
mutation AddInternalSKU {
productUpdate(
input: {
id: "gid://shopify/Product/123456789"
metafields: [
{
namespace: "$app"
key: "internal_sku"
value: "INV-2024-COTTON-001"
type: "single_line_text_field"
}
]
}
) {
product { id metafield(namespace: "$app", key: "internal_sku") { id value } }
userErrors { field message }
}
}
```
### Merchant-owned metafields
Merchant-owned definitions **can't** be created in `shopify.app.toml`. Create them with `metafieldDefinitionCreate` using any non-reserved namespace (`custom`, `specs`, `inventory`):
```graphql
mutation {
metafieldDefinitionCreate(definition: {
name: "Warranty Information",
namespace: "custom",
key: "warranty_info",
type: "multi_line_text_field",
ownerType: PRODUCT,
access: { storefront: PUBLIC_READ, },
}) {
createdDefinition { name namespace key type access }
}
}
```
### App-data metafields
App-data metafields are stored on the `AppInstallation` resource and are completely hidden from the admin; only the owning app can access them (via GraphQL or the `app` object in Liquid). The `$app` namespace isn't required because the `AppInstallation` owner provides isolation. Retrieve the installation ID with the `currentAppInstallation` query, then create the value with `metafieldsSet`.
### Permissions (`access` settings)
* `admin` controls the Shopify admin and GraphQL Admin API. For app-owned: `access.admin = "merchant_read"` (view only, default) or `"merchant_read_write"` (view and edit); GraphQL enums `MERCHANT_READ` / `MERCHANT_READ_WRITE`. Merchant-owned metafields always have full access.
* `storefront` controls the Storefront API: `access.storefront = "none"` (default) or `"public_read"`; GraphQL enums `NONE` / `PUBLIC_READ`. This does **not** affect Liquid - metafields are always accessible in Liquid regardless of this setting.
* `customer_account` controls the Customer Accounts API: `"none"` / `"read"` / `"read_write"`; GraphQL enums `NONE` / `READ` / `READ_WRITE`.
## When To Use
* Use **app-owned** metafields for app-managed logic, configuration, and workflows.
* Use **merchant-owned** metafields to extend existing store data that merchants and other apps should share and edit.
* Use **app-data** metafields for per-installation configuration hidden from merchants (but store sensitive credentials in a secure database or secret manager, not here).
* Use **metaobjects** when you need standalone, structured records with multiple related fields.
## Risks & Pitfalls
* Merchant-owned definitions cannot be created in `shopify.app.toml` - only through GraphQL or the admin.
* App-data metafields are not for sensitive credentials; use environment variables or a dedicated secret management system.
* Customer Account API access levels can only be adjusted via GraphQL Admin API mutation for app-owned metafields (namespace `app--`); for merchant-owned, configure it through the Shopify admin.
* Metafield access ultimately depends on its owning resource.
## Related Concepts
* [[concepts/admin-graphql-api|Admin GraphQL API]] - the primary API for defining and setting metafields
* [[concepts/liquid|Liquid]] - metafields are always readable in Liquid via the `app` and resource objects
* [[concepts/storefront-api|Storefront API]] - reads metafields marked `public_read`
* [[concepts/building-apps|Building apps]] - `shopify.app.toml` app configuration
## Sources
- `raw/web_community-custom-data-md.md`
- `raw/web_community-metafields-md.md`
---
title: "Shopify Functions"
type: concept
tags: [functions, wasm, discounts, checkout, backend-logic, limits]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-function-apis.md"]
source_url: "https://shopify.dev/docs/api/functions"
confidence: high
---
## Definition
Shopify Functions enable you to customize Shopify's backend logic by running custom
code during the checkout process. You can create functions to implement specialized
features that aren't available natively - for example, generate custom delivery
options, create new types of discounts, and provide your own validation of a cart
and checkout. Because functions run in the context of key purchase flows, you must
prioritize performance: delays can negatively impact the Shopify backend and prevent
customers from making purchases.
## How It Works
Function APIs require a set of essential files: a TOML configuration, a GraphQL
schema, a GraphQL input query, and function code. Use
[[concepts/shopify-cli|Shopify CLI]] to scaffold these elements.
**Function anatomy.** When you create a function you write a GraphQL input query
that defines the shape of your data, then write logic that transforms the input and
returns output to Shopify.
- **Input** - the `Input` object is the complete GraphQL schema your function can
receive. Before calling your target, Shopify runs the associated input query and
passes the resulting JSON to your target. The CLI generates a `run.graphql` input
query you can edit; the JSON in `input.json` then matches that query's shape.
Input queries can be customized with metafields, app-owned metaobjects, or input
variables. Each target can have a unique input query.
- **Function** - the logic that processes input into a standardized, declarative
response: an ordered list of operations, each specifying an action based on the
function's purpose.
- **Output** - a declarative object representing operations for Shopify to execute.
Each Function API extension target specifies the output shape using a GraphQL type.
You can write functions in any language that compiles to WebAssembly (Wasm),
although **Rust is recommended and strongly preferred** as the most performant
choice to avoid failing with large carts.
**Execution order in checkout.** Functions execute in a specific sequence, each
depending on data from earlier steps: first functions that change pricing and
presentation of cart items run, then functions that calculate discounts, and
finally functions that validate cart contents. A cart validation function can't run
until after discount calculations are complete.
**Target types.** Targets are identifiers that specify where you inject code into
Shopify:
- **Run target** - an extension point that customizes Shopify's backend with custom
business logic (for example prioritize locations for order routing, or create a
new discount type). It uses Shopify data, hardcoded values, or fetch results.
- **Fetch target** (limited access) - retrieves data from a third-party provider
and passes it to the run target; Shopify makes the HTTP call on your behalf before
the run target. Limited to custom apps installed on Enterprise stores and requires
network access; not available on development stores or in developer preview.
## Key Parameters
Configuration lives in `shopify.extension.toml`. Function-specific properties:
- `[[extensions.targeting]]` (required) - contains `target` (required; where code is
injected into the backend), `input_query` (optional; path to the input query
file - omit and the function receives no input), and `export` (optional; the Wasm
export that executes the target). Functions don't use
`extensions.targeting.module`; use `export` instead. Defaults to `_start`.
- `[extensions.build]` (optional) - `command` (required; build command invoked by
the CLI, omittable for JavaScript), `path` (optional; relative path to the Wasm
module, e.g. `build/my-module.wasm`, defaults to `dist/index.wasm`), `watch`
(optional; paths the CLI watches - defaults to `['src/**/*.js', 'src/**/*.ts']`
for JS/TS; no `../` parent references), and `wasm_opt` (optional; optimize before
upload, defaults to `true`).
- `[extensions.ui]` / `[extensions.ui.paths]` (optional) - `handle`, `enable_create`,
and `create` / `details` App Bridge paths for the function's merchant interface.
- `[extensions.input.variables]` (optional) - `namespace` and `key` for variables
used with `hasTags` and `hasCollections` in the input query.
**Schema and versioning.** Each function includes a copy of the GraphQL schema in
`schema.graphql`. Function APIs are versioned; updates release quarterly. Regenerate
with the `function schema` command (use `--stdout` to output to STDOUT).
**API availability.** All plans: stores on any plan can use public App Store apps
that contain functions. Shopify Plus: only Plus stores can use custom apps that
contain Shopify Function APIs.
## When To Use
Use Functions to customize backend behavior in purchase flows: discounts, delivery/
shipping options, payment customization, order routing, and cart-and-checkout
validation. For merchant-facing configuration of a function, pair it with an
[[concepts/app-extensions|admin UI extension]] (Function settings target).
## Risks & Pitfalls
- Apps can reference only their own functions in Admin API mutations such as
`discountAutomaticAppCreate` and `cartTransformCreate`; referencing another app's
function returns a `Function not found` error.
- Nondeterminism isn't allowed - no randomizing or clock functionality.
- You can't debug by printing to STDOUT or STDERR.
- The App Store doesn't permit apps that provide dynamic editing and execution of
function code.
- **Fixed limits:** compiled binary size 256 kB; runtime linear memory 10,000 kB;
runtime stack memory 512 kB; logs written 1 kB (truncated). (Limits treat 1 kB as
1000 bytes.)
- **Dynamic limits (up to 200 line items; scale beyond that):** execution
instruction count 11 million instructions; function input 128 kB; function output
20 kB.
- **Input query limits:** max input query size 3000 bytes (excluding comments);
metafields over 10,000 bytes aren't returned; `list`-type field arguments and
variables can't exceed 100 elements; maximum calculated input query cost of 30.
## Related Concepts
- [[concepts/app-extensions|App extensions]]
- [[concepts/building-apps|Building apps]]
- [[concepts/admin-graphql-api|Admin GraphQL API]]
- [[concepts/custom-data-and-metafields|Custom data and metafields]]
- [[concepts/shopify-cli|Shopify CLI]]
## Sources
- raw/web_community-function-apis.md
---
title: "Hydrogen and Headless Commerce"
type: concept
tags: [hydrogen, headless, oxygen, storefront-api, react, custom-storefronts]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-hydrogen-md.md", "raw/web_community-hydrogen-md-2.md", "raw/web_community-headless-md.md", "raw/web_community-getting-started-md.md"]
confidence: high
---
# Hydrogen and Headless Commerce
## Definition
Headless commerce gives you all the power of Shopify under the hood with complete control over the frontend. You can start quickly with **Hydrogen**, Shopify's official headless framework, or add Shopify APIs to your existing tech stack. **Hydrogen** is Shopify's opinionated stack for headless commerce, built on React Router; it provides tools, utilities, and best-in-class examples for building dynamic, performant commerce applications. **Oxygen** is Shopify's global edge hosting platform where you deploy Hydrogen apps for free, with continuous deployment, push-to-preview, and instant rollbacks.
## How It Works
Two paths exist for headless:
* **Hydrogen and Oxygen** - Shopify's batteries-included framework plus free edge hosting. Hydrogen includes a suite of components and utilities pre-wired for Shopify APIs. It is built on React Router, so server-side rendering, progressive enhancement, and nested routes come standard.
* **Bring your own stack** - use any language, framework, or hosting. Install the Headless sales channel to create storefronts and manage API tokens and permissions. Storefront Web Components let you sell products anywhere with a few lines of embedded HTML.
Hydrogen authenticates with and makes requests to the [[concepts/storefront-api|Storefront API]] and the Customer Account API; it includes full-featured API clients to handle queries and mutations securely. Both APIs offer public credentials for client-side applications. Create access tokens by installing the **Hydrogen sales channel** (built-in Oxygen support) or the **Headless sales channel** (host anywhere).
Hydrogen re-exports many components, hooks, and utilities from **Hydrogen React**, an underlying framework-agnostic package. When building a Hydrogen app, import modules from the `@shopify/hydrogen` package:
```jsx
import {ShopPayButton} from '@shopify/hydrogen';
export function renderShopPayButton({variantId, storeDomain}) {
return ;
}
```
## Key Parameters
### Requirements
* Node.js v16.20+ and npm v8.19+
* Hydrogen channel (installed from the Shopify App Store)
### Create a new Hydrogen project
```txt
npm create @shopify/hydrogen@latest
```
To scaffold with example data from Mock.shop, add the `--quickstart` flag (shorthand for a set of recommended options for trying Hydrogen):
```text
npm create @shopify/hydrogen@latest -- --quickstart
```
### Setup workflow (getting started)
1. **Run the dev server**:
```text
cd hydrogen-quickstart
shopify hydrogen dev
```
Open `http://localhost:3000` to see Mock.shop inventory.
2. **Link the project to Shopify** (log in and create a storefront):
```text
npx shopify hydrogen link
```
3. **Pull environment variables**:
```text
npx shopify hydrogen env pull
```
This populates variables such as `PUBLIC_STOREFRONT_ID`, `PUBLIC_STOREFRONT_API_TOKEN`, `PRIVATE_STOREFRONT_API_TOKEN`, `PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID`, and `PUBLIC_CUSTOMER_ACCOUNT_API_URL`.
4. **Deploy to Oxygen** (select the **Preview** environment at the prompt):
```text
npx shopify hydrogen deploy
```
### Authenticating a Hydrogen app
Create a storefront client in `server.js`:
```js
const {storefront} = createStorefrontClient({
cache,
waitUntil,
i18n: {language: 'EN', country: 'US'},
publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN,
privateStorefrontToken: env.PRIVATE_STOREFRONT_API_TOKEN,
storeDomain: env.PUBLIC_STORE_DOMAIN,
storefrontId: env.PUBLIC_STOREFRONT_ID,
storefrontHeaders: getStorefrontHeaders(request),
});
```
A typical `.env` for the demo store:
```txt
SESSION_SECRET="foobar"
PUBLIC_STOREFRONT_API_TOKEN="3b580e70970c4528da70c98e097c2fa0"
PUBLIC_STORE_DOMAIN="hydrogen-preview.myshopify.com"
```
### Versioning
Hydrogen is tied to specific versions of the Storefront API, which is versioned quarterly. If you use Storefront API version `2023-10`, then Hydrogen versions `2023.10.x` are fully compatible. If a Storefront API version includes breaking changes, the corresponding Hydrogen version includes the same breaking changes.
## When To Use
* Choose **Hydrogen and Oxygen** when you want a fast, opinionated React storefront with free hosting and pre-built Shopify-aware components.
* Choose **bring your own stack** (Headless channel + Storefront API) when you need a specific language, framework, or hosting provider, or must integrate Shopify into existing infrastructure.
* Choose **Liquid themes** instead when you want a merchant-customizable Online Store storefront without running your own frontend - see [[syntheses/liquid-themes-vs-hydrogen|Liquid themes vs Hydrogen]].
## Risks & Pitfalls
* Hydrogen's version is locked to a Storefront API version; a breaking Storefront API release carries the same breaking changes into Hydrogen.
* Public tokens are for client-side use; keep private tokens (`PRIVATE_STOREFRONT_API_TOKEN`) server-side.
* The `--quickstart` flag connects to Mock.shop example data; you must link your project and pull env vars to show real store inventory.
## Related Concepts
* [[concepts/storefront-api|Storefront API]] - the API Hydrogen queries for storefront data
* [[concepts/shopify-cli|Shopify CLI]] - the `shopify hydrogen` command topic
* [[concepts/liquid|Liquid]] - the alternative, theme-based rendering approach
* [[syntheses/liquid-themes-vs-hydrogen|Liquid themes vs Hydrogen]] - decision framework
## Sources
- `raw/web_community-hydrogen-md.md`
- `raw/web_community-hydrogen-md-2.md`
- `raw/web_community-headless-md.md`
- `raw/web_community-getting-started-md.md`
---
title: "Liquid Template Language"
type: concept
tags: [liquid, themes, templating, syntax, storefront]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-liquid-md.md"]
confidence: high
---
# Liquid Template Language
## Definition
Liquid is a template language created by Shopify. It is available as an open source project on GitHub and is used by many software projects. A template language lets you create a single template of static content and dynamically insert information depending on where the template is rendered - for example, a product template that hosts standard attributes (image, title, price) and renders them for the current product being viewed. Liquid is the language used to build [[concepts/themes-architecture|Shopify themes]]. It dynamically outputs objects and their properties, and you modify that output with logic (tags) or filters.
The variation documented here extends open-source Liquid for Shopify themes. Shopify uses slightly different Liquid variations for notification templates, Shopify Flow, order printer templates, and packing slip templates - those are not part of the theme reference.
## How It Works
Liquid has three building blocks: **objects** (variables you output), **tags** (logic), and **filters** (output modifiers). Objects and properties output using one of six basic data types, and Liquid includes basic logical and comparison operators for use with tags.
### Objects - output with `{{ }}`
Double curly brace delimiters denote an output. To output an object, wrap it in `{{ }}`; access a property with dot notation:
```liquid
{{ product.title }}
```
Object types include store resources (a collection or product and its properties), standard content that powers themes (such as `content_for_header`), and functional elements (such as `paginate` and `search`).
Objects can be accessed in three ways:
* **Globally**: available in any Liquid file, excluding `checkout.liquid` and Liquid asset files.
* **In templates**: available in specific templates and their sections or blocks (for example, the `product` object in a product template).
* **Through parent objects**: returned as properties of other objects (for example, `article` objects through `articles` or `blog`).
### Tags - logic with `{% %}`
Tags are wrapped with curly brace percentage delimiters `{% %}`. The text within is an instruction, not content to render.
```liquid
{% if product.available %}
Price: $99.99
{% else %}
Sorry, this product is sold out.
{% endif %}
```
To nest multiple tags inside one set of delimiters, use the `liquid` tag.
#### Tags with parameters
Some tags accept required or optional parameters. For example, the `for` tag takes an optional `limit`:
```liquid
{% assign numbers = '1,2,3,4,5' | split: ',' %}
{% for item in numbers limit:2 -%}
{{ item }}
{% endfor %}
```
That outputs `1` and `2`.
### Filters - modify output with `|`
To filter the output of a tag, use the pipe character `|` followed by the filter. Here `product` is the object, `title` the property, and `upcase` the filter:
```liquid
{{ product.title | upcase }}
```
`Health potion` becomes `HEALTH POTION`.
#### Filters with parameters
Many filters accept parameters, some required and some optional:
```liquid
{{ product.title | remove: 'Health' }}
```
`Health potion` becomes `potion`.
#### Chaining multiple filters
Multiple filters can be used on one output and are applied from left to right:
```liquid
{{ product.title | upcase | remove: 'HEALTH' }}
```
`Health potion` becomes `POTION`.
### Creating variables
Use variable tags like `assign` or `capture` to create your own variables. Syntactically, Liquid treats variables the same as objects:
```liquid
{% assign my_variable = 'My custom string.' %}
{{ my_variable }}
```
## Key Parameters
### Whitespace control
Add a hyphen to a tag's delimiters (`{%- -%}` or `{{- -}}`) to strip surrounding whitespace. Example combining output and conditional logic:
```liquid
{{ page_title }}
{% if page_description -%}
{%- endif %}
```
### Delimiter summary
* `{{ }}` - output an object or variable.
* `{% %}` - logic tag (instruction, not rendered).
* `{%- -%}` / `{{- -}}` - strip whitespace on the hyphenated side.
* `|` - apply a filter to output.
* `{% # comment %}` - inline comment inside a tag.
## When To Use
Use Liquid whenever you build or customize a Shopify theme: layouts, templates, sections, blocks, and snippets are all Liquid files. Liquid renders dynamic storefront content server-side. For fully custom, React-based storefronts that call APIs instead of rendering Liquid, see [[concepts/hydrogen-and-headless|Hydrogen and headless]].
## Risks & Pitfalls
* Objects are **not** available globally in `checkout.liquid` or in Liquid asset files.
* Variables created outside a section aren't accessible within it, and section/block objects aren't available outside their section (except in a snippet rendered inside that section).
* This theme Liquid reference does not cover the Flow, notification, order-printer, or packing-slip Liquid variations.
## Related Concepts
* [[concepts/themes-architecture|Themes architecture]] - where Liquid files live and how they combine
* [[concepts/custom-data-and-metafields|Custom data and metafields]] - metafields are always readable in Liquid
* [[syntheses/liquid-themes-vs-hydrogen|Liquid themes vs Hydrogen]] - choosing Liquid rendering vs a React storefront
## Sources
- `raw/web_community-liquid-md.md`
---
title: "Shopify CLI"
type: concept
tags: [shopify-cli, tooling, apps, themes, command-line]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-shopify-cli-md.md"]
confidence: high
---
# Shopify CLI
## Definition
Shopify CLI is a command-line interface tool that helps you generate and work with Shopify apps, themes, and custom storefronts. You can also use it to automate many common development tasks. It is open source.
## How It Works
Shopify CLI groups commands into topics. The command syntax is `shopify [topic] [command]`. Run `shopify` (with no arguments) in your terminal to discover available commands, or run the `help` command:
```sh
shopify help
```
Command topics include `app` (build and deploy apps), `theme` (build, preview, push, and pull themes), and `hydrogen` (create, run, link, and deploy Hydrogen storefronts). Verbatim commands documented in the source set include `shopify app deploy` (deploy an app and its configuration), and the Hydrogen topic `shopify hydrogen dev`, `shopify hydrogen link`, `shopify hydrogen env pull`, and `shopify hydrogen deploy` (see [[concepts/hydrogen-and-headless|Hydrogen and headless]]). Refer to each topic section in the CLI documentation sidebar for the full command list.
## Key Parameters
### Requirements
* Node.js: 22.12 or higher
* A Node.js package manager: npm, Yarn 1.x, or pnpm
* Git: 2.28.0 or higher
### Installation
Installing globally lets you run `shopify` commands from any directory:
```sh
# npm
npm install -g @shopify/cli@latest
# yarn
yarn global add @shopify/cli@latest
# pnpm
pnpm install -g @shopify/cli@latest
```
On macOS you can also install via Homebrew:
```sh
brew tap shopify/shopify
brew install shopify-cli
```
### Upgrading
Starting with Shopify CLI 4.0, the CLI upgrades itself automatically using the package manager you installed it with. Auto-upgrade is skipped in CI environments, project-local installs, and major version bumps. To upgrade immediately:
```sh
shopify upgrade
```
Manage auto-upgrade behavior:
```sh
# Disable
shopify config autoupgrade off
# Re-enable
shopify config autoupgrade on
# Check status
shopify config autoupgrade status
# Check version
shopify version
```
When auto-upgrade is off, the CLI shows a daily reminder when a new version is available but won't upgrade itself.
### Network proxy configuration
When behind a network proxy (CLI version 3.78+), set environment variables to route connections:
```bash
# HTTP traffic
export SHOPIFY_HTTP_PROXY=http://proxy.com:8080
# Optional separate HTTPS proxy (falls back to HTTP proxy if unset)
export SHOPIFY_HTTPS_PROXY=https://secure-proxy.com:8443
# Authenticated proxy: include credentials in the URL
export SHOPIFY_HTTP_PROXY=http://username:password@proxy.com:8080
```
### Usage reporting
Anonymous usage statistics are collected by default. To opt out, set either `SHOPIFY_CLI_NO_ANALYTICS=1` or `OPT_OUT_INSTRUMENTATION=true`.
## When To Use
* Use the `app` topic (for example `shopify app deploy`) when building and deploying apps and app extensions.
* Use the `theme` topic when developing themes locally, previewing, and pushing/pulling theme files.
* Use the `hydrogen` topic when scaffolding, running, linking, and deploying Hydrogen custom storefronts.
## Risks & Pitfalls
* Requires Node.js 22.12+ and Git 2.28.0+; older versions may fail to install or run.
* Auto-upgrade (CLI 4.0+) does not run in CI, for project-local installs, or across major version bumps - upgrade those manually with `shopify upgrade`.
* Analytics are on by default; opt out explicitly via the environment variables above if required.
## Related Concepts
* [[concepts/building-apps|Building apps]] - the `shopify app` command topic and app scaffolding
* [[concepts/themes-architecture|Themes architecture]] - what the `shopify theme` commands operate on
* [[concepts/hydrogen-and-headless|Hydrogen and headless]] - the `shopify hydrogen` command topic
* [[concepts/custom-data-and-metafields|Custom data and metafields]] - `shopify app deploy` ships metafield definitions
## Sources
- `raw/web_community-shopify-cli-md.md`
---
title: "Storefront API"
type: concept
tags: [storefront-api, graphql, headless, buyer-facing, custom-storefronts, foundational]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-storefront-md.md", "raw/web_community-authentication-md.md"]
confidence: high
---
## Definition
The Storefront API is Shopify's GraphQL API for building buyer-facing shopping experiences on any platform -- "the web, apps, and games." It "provides commerce primitives to build custom, scalable, and performant shopping experiences," letting customers view products and collections, add products to a cart, and check out. It is the data layer for headless and custom storefronts (including [[concepts/hydrogen-and-headless|Hydrogen]]). Unlike the [[concepts/admin-graphql-api|Admin API]], it exposes buyer-facing (unauthenticated) data and is designed to be safely queryable from clients like browsers.
## How It Works
**Endpoint.** "The Storefront API is available only in GraphQL. There's no REST API for storefronts." All queries hit a single versioned endpoint that only accepts `POST`:
`https://{store_name}.myshopify.com/api/2026-07/graphql.json`
Note the path is `/api/...`, not the Admin API's `/admin/api/...`.
**Authentication.** The Storefront API "supports both tokenless access and token-based authentication."
- **Tokenless access** allows queries without an access token, covering "essential features": Products and Collections, Selling Plans, Search, Pages/Blogs/Articles, and Cart (read/write). "Tokenless access has a query complexity limit of 1,000."
- **Token-based access** is required "for access to all Storefront API features," including Product Tags, Metaobjects and Metafields, Menu (Online Store navigation), and Customers. Two types:
- **Public access:** "query the API from a browser or mobile app." Send the `X-Shopify-Storefront-Access-Token` header.
- **Private access:** "query the API from a server or other private context, like a Hydrogen backend." Send the `Shopify-Storefront-Private-Token` header; when serving buyer traffic also send `Shopify-Storefront-Buyer-IP` (case-sensitive). See [[concepts/authentication-and-access]].
Example verbatim tokenless request:
```bash
curl -X POST \
https://{shop}.myshopify.com/api/2026-07/graphql.json \
-H 'Content-Type: application/json' \
-d '{
"query": "{ products(first: 3) { edges { node { id title } } } }"
}'
```
Token-based requests add `-H 'X-Shopify-Storefront-Access-Token: {storefront-access-token}'`.
**Frameworks and SDKs.** Hydrogen (React framework), the Storefront API Client (`@shopify/storefront-api-client`, recommended for custom storefronts without Hydrogen), React Router apps, Node.js and Ruby libraries, and mobile Buy SDKs for Android and iOS.
**Directives.** The `@inContext` directive contextualizes queries by country (`@inContext(country: FR)`), language (`@inContext(language: ES)`, since 2022-04), buyer identity (since 2024-04), and visitor consent (since 2025-10). The `@defer` directive streams part of a query first (available as a developer preview in `unstable`).
## Key Parameters
- **Endpoint:** `https://{store_name}.myshopify.com/api/2026-07/graphql.json` (`POST` only).
- **Version cited:** `2026-07`; "versioned, with new releases four times a year."
- **Public token header:** `X-Shopify-Storefront-Access-Token`.
- **Private token header:** `Shopify-Storefront-Private-Token` (+ `Shopify-Storefront-Buyer-IP`, case-sensitive).
- **Tokenless complexity limit:** 1,000 (exceeding it returns `MAX_COMPLEXITY_EXCEEDED`).
- **Token cap:** max 100 active storefront access tokens per shop (per [[concepts/authentication-and-access]]).
- **Unauthenticated scopes** gate token-based data (for example `unauthenticated_read_product_listings`).
## When To Use
- Building a headless / custom storefront for web, mobile, games, or any non-theme surface.
- Any buyer-facing read of products, collections, or search, and cart/checkout flows.
- Using Hydrogen or the Storefront API Client for a JavaScript storefront.
- Localizing pricing/language/buyer context via `@inContext`.
- When you specifically need buyer-scoped (not merchant-scoped) data -- for admin/merchant data use the [[concepts/admin-graphql-api]] instead. See [[syntheses/admin-vs-storefront-api]].
## Risks & Pitfalls
- **Returns `200 OK` on errors.** Like the Admin GraphQL API, "the Storefront API can return a `200 OK` response code in cases that would typically produce 4xx errors in REST." Inspect the `errors` object.
- **Tokenless complexity ceiling.** "When using tokenless access, query complexity that exceeds 1,000 will result in an error" (`MAX_COMPLEXITY_EXCEEDED`). Reduce query cost or use token-based access.
- **Bot rate limiting and security rejection.** Real buyer traffic "isn't subject to a fixed request-per-minute limit," but automated traffic is rate-limited; malicious-looking requests get a `430 Shopify Security Rejection`. Bots needing higher limits should sign requests with Web Bot Auth. Always include the correct Buyer IP header.
- **Do not leak private tokens client-side** (see [[concepts/authentication-and-access]]).
- **Feature restrictions.** "You can't use Storefront API to duplicate existing Shopify functionality -- be sure to check the API terms of service." Shopify Plus bot protection is only available for the Cart object, not Checkout. No bulk operations (Admin API only).
## Related Concepts
- [[concepts/admin-graphql-api]]
- [[concepts/authentication-and-access]]
- [[concepts/hydrogen-and-headless]]
- [[concepts/api-usage]]
- [[concepts/what-is-shopify-dev]]
- [[syntheses/admin-vs-storefront-api]]
## Sources
- raw/web_community-storefront-md.md (Storefront API reference, api_version 2026-07 -- https://shopify.dev/docs/api/storefront/latest)
- raw/web_community-authentication-md.md (Access tokens for the Storefront API -- https://shopify.dev/docs/api/usage/authentication)
---
title: "Theme Architecture: Layouts, Templates, Sections, and Blocks"
type: concept
tags: [themes, architecture, sections, blocks, templates, online-store-2.0]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-architecture-md.md", "raw/web_community-templates-md.md", "raw/web_community-layouts-md.md", "raw/web_community-sections-md.md", "raw/web_community-blocks-md.md"]
confidence: high
---
# Theme Architecture: Layouts, Templates, Sections, and Blocks
## Definition
A theme controls the organization, features, and style of a merchant's online store. Theme code is organized with a standard directory structure of files specific to Shopify themes, plus supporting assets (images, stylesheets, scripts). Theme files fall into three categories: **markup and features** (Liquid files that generate page HTML), **supporting assets** (assets, scripts, locale files), and **config files** (JSON configuration customizable in the theme editor).
## How It Works
Each page is organized by nested components working together:
| # | Component | Description |
| - | - | - |
| 1 | Layout file | The base of the theme. Hosts repeated elements like headers and footers. |
| 2 | Template | Controls what's displayed on a page. JSON templates act only as a wrapper for sections; Liquid templates contain code. |
| 3 | Section groups | Containers that let merchants add, remove, and reorder sections in areas like the header and footer. |
| 4 | Sections | Reusable, customizable modules of content added to JSON templates and section groups. |
| 5 | Blocks | Reusable modules within a section that can be added, removed, and reordered. |
| 6 | Snippets | Reusable pieces of Liquid code rendered anywhere in the theme. |
### Directory structure
Themes must use this directory structure (subdirectories other than these aren't supported):
```text
.
├── assets
├── blocks
├── config
├── layout
├── locales
├── sections
├── snippets
└── templates
└── customers
└── metaobject
```
Only a `layout` directory containing a `theme.liquid` file is required for the theme to be uploaded to Shopify. Directory roles: `assets` (image/CSS/JS; reference with the `asset_url` filter; non-binary files gain limited Liquid via a `.liquid` extension such as `.js.liquid`/`.css.liquid`), `config` (config files and theme settings, read via the `settings` object), `layout` (must contain `theme.liquid`), `locales` (translations), `sections`, `snippets`, and `templates` (`templates/customers` holds legacy customer account pages).
## Key Parameters
### Layouts
Layouts are Liquid files rendered as the base for all templates. Edit the default `theme.liquid` or create custom layout files. JSON templates specify the layout via the `layout` attribute; Liquid templates use the `layout` tag. Two subtypes exist: **General** (all non-checkout pages; `theme.liquid` is required in all themes) and **Checkout** (`checkout.liquid`, Shopify Plus only). A minimal layout:
```liquid
...
{{ content_for_header }}
...
...
{{ content_for_layout }}
...
```
`content_for_header` is required in `theme.liquid` and must be placed inside ``; it loads Shopify's required scripts (do not modify or parse it). `content_for_layout` outputs each template's content and must be placed between `` and ``. Both are required in `theme.liquid` - without them you can't save the file via the code editor or Shopify CLI.
### Templates - JSON vs Liquid
Templates control what's rendered on each page type. There are two file types:
* **JSON** (`.json`) - data files that populate the template with sections, which merchants can add, remove, and rearrange in the theme editor. Any HTML/Liquid must live in a referenced section. Preferred when using sections.
* **Liquid** (`.liquid`) - Liquid markup files; add Liquid and HTML directly.
You can have a maximum of 1000 JSON templates across all types. No template types are required, but you need a matching template for any page type you render (for example, at least one `product` template). Template types include `404`, `article`, `blog`, `cart`, `collection`, `index`, `list-collections`, `page`, `password`, `product`, `search`, and `metaobject` (rendered at `metaobject/{metaobject-type}`, e.g. `metaobject/book`). Certain templates **can't** be JSON and must be Liquid: `gift_card.liquid`, `robots.txt.liquid`, `agents.md.liquid`, `llms.txt.liquid`, and `llms-full.txt.liquid`. Legacy customer account templates (`customers/account`, `customers/login`, etc.) are deprecated; use the `` component instead.
### Sections
Sections are Liquid files in the `sections` directory that create reusable, merchant-customizable modules. JSON templates and section groups can render up to **25 sections**, and each section can have up to **50 blocks**. A section can contain three content types: **main content** (HTML/Liquid with access to global objects plus the section-specific `section` and `block` objects), **assets** (bundled via the `{% javascript %}` and `{% stylesheet %}` tags), and **schema** (the required `{% schema %}` tag defining `name`, `tag`, `class`, `limit`, `settings`, `blocks`, `max_blocks`, `presets`, `default`, `locales`, `enabled_on`, `disabled_on`). Render a section by referencing it in a JSON template or section group, statically with the `section` tag, or via the Section Rendering API:
```liquid
{% section 'featured-product' %}
```
Avoid static rendering where possible - statically rendered sections can't be removed or reordered by merchants, and only one instance exists even if included in multiple files. Section and block files must define `presets` in schema to be addable in the theme editor.
### Blocks
Blocks break sections into smaller reusable pieces of Liquid, each with its own settings, addable/removable/reorderable within a section. There are three types:
* **Theme blocks** - their own Liquid files in `/blocks`, reusable across multiple sections; support nesting and static blocks. A theme can contain at most **300 theme blocks** (every `.liquid` file in `/blocks` counts, including AI-generated and unreferenced blocks).
* **Section blocks** - defined within a section's Liquid file, limited to that section, single level of hierarchy (no nesting), and can't be mixed with theme blocks in the same section.
* **App blocks** - provided by installed apps. Support them in schema with the `@app` type; use `@theme` for theme blocks:
```js
{% schema %}
{
"name": "Slide",
"blocks": [{ "type": "@theme" }, { "type": "@app" }],
```
**Theme blocks vs snippets**: theme blocks show settings in the theme editor, let merchants customize each instance, and access the parent section and global objects but can't receive variables from parent code. Snippets handle repeatable markup without merchant customization, accept variables from parent code, and don't show in the editor. AI-generated theme blocks (via Sidekick) are stored in `/blocks` and are treated as theme blocks.
## When To Use
* Use **JSON templates** when you want sections that merchants can add, remove, and reorder (Online Store 2.0). They also minimize `settings_data.json` and improve editor performance.
* Use **Liquid templates** when you need to add Liquid/HTML directly and don't need section reordering.
* Use **theme blocks** for reusable, mergeable structure across sections; use **snippets** for repeatable markup driven by parent variables.
## Risks & Pitfalls
* Subdirectories beyond the standard set aren't supported.
* Removing `content_for_header` or `content_for_layout` from `theme.liquid` blocks saving via the editor or CLI.
* `checkout.liquid` is deprecated for the Thank you and Order status pages (sunset August 28, 2025); migrate to Checkout Extensions.
* Limits are hard: 25 sections per template/group, 50 blocks per section, 300 theme blocks per theme, 1000 JSON templates.
* Certain templates (`gift_card`, `robots.txt`, `agents.md`, `llms.txt`, `llms-full.txt`) must be Liquid, not JSON.
## Related Concepts
* [[concepts/liquid|Liquid]] - the language all theme markup files use
* [[concepts/custom-data-and-metafields|Custom data and metafields]] - metaobject templates and settings
* [[concepts/shopify-cli|Shopify CLI]] - theme dev, push, and pull commands
* [[syntheses/liquid-themes-vs-hydrogen|Liquid themes vs Hydrogen]] - themes vs custom React storefronts
## Sources
- `raw/web_community-architecture-md.md`
- `raw/web_community-templates-md.md`
- `raw/web_community-layouts-md.md`
- `raw/web_community-sections-md.md`
- `raw/web_community-blocks-md.md`
---
title: "Webhooks"
type: concept
tags: [webhooks, topics, subscriptions, hmac, gdpr-compliance]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-webhooks-md.md", "raw/web_community-webhooks-md-2.md"]
source_url: "https://shopify.dev/docs/apps/build/webhooks"
confidence: high
---
## Definition
When your app needs information about specific events on a shop, it can subscribe
to Shopify webhook topics to receive near-real-time data about those events.
Webhooks keep your app in sync with Shopify data or trigger an additional action
after an event occurs, and are a performant alternative to continuously polling for
changes.
## How It Works
The `orders/create` topic illustrates the flow:
1. The app subscribes to the `orders/create` topic for a shop and listens for order
creation events.
2. The app specifies an endpoint to receive webhooks for the topic (for example an
HTTPS endpoint hosted by the app server).
3. An order is created from that shop.
4. This triggers a webhook to be published to the `orders/create` topic.
5. Shopify sends that webhook, including headers and an order payload, to the
specified subscription endpoint.
Four core concepts: **Manage subscriptions** (which topics, and where deliveries
go), **Delivery filtering** (`filter` and `include_fields` narrow which deliveries
qualify and what each payload contains), **Delivery structure** (payload format and
headers), and **Verify deliveries** (verify HMAC signatures and ignore duplicates).
## Key Parameters
**Terminology.** A *webhook subscription* declares which topic to watch and where
to send deliveries: a URL, Google Pub/Sub URI, or Amazon EventBridge ARN. A
*webhook topic* identifies the resource and action that qualifies a delivery (for
example `products/create` fires when a new product is created).
**Subscribing via app configuration file** (CLI 3.63.0 or greater). Subscriptions
in the app config apply across all shops the app is installed on:
```toml
[webhooks]
api_version = "2023-04"
[[webhooks.subscriptions]]
topics = [
"products/create",
"products/update",
"products/delete"
]
uri = "pubsub://example:pub-sub-topic1"
[[webhooks.subscriptions]]
topics = ["orders/create"]
uri = "pubsub://example:pub-sub-topic2"
```
**Subscribing via the GraphQL Admin API.** For shop-specific subscriptions to
non-compliance topics, use the `webhookSubscriptionCreate` mutation, specifying the
`$topic` and `$webhookSubscription` parameters:
```graphql
mutation webhookSubscriptionCreate($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
webhookSubscription {
id
topic
format
includeFields
uri
}
}
}
```
**Topics** name a resource and action as `resource/action`. Examples from the topic
list include: `app/uninstalled`, `app/scopes_update`, `carts/create`,
`carts/update`, `checkouts/create`, `checkouts/update`, `collections/create`,
`companies/create`, `customers/create`, `customers/update`, `customers/merge`,
`discounts/create`, `fulfillments/create`, `fulfillments/update`,
`inventory_levels`/locations topics, `locations/activate`, `markets/create`,
`metaobjects/create`, `orders/cancelled`, `orders/create`, `orders/edited`,
`orders/fulfilled`, `orders/paid`, `orders/updated`, `products/create`,
`products/update`, `products/delete`, `refunds/create`, `returns/request`,
`returns/approve`, `segments/create`, `shop/update`, and `themes/publish`. Each
topic requires the relevant access scope.
**Headers.** Each delivery includes metadata headers such as `X-Shopify-Topic`,
`X-Shopify-Webhook-Id`, and `X-Shopify-Hmac-Sha256`.
## Verification and compliance
**HMAC verification.** Verify HMAC signatures on each delivery and ignore duplicate
deliveries using the `X-Shopify-Webhook-Id` header (see Verify deliveries). This
confirms a delivery genuinely came from Shopify and lets you deduplicate retries.
**Mandatory GDPR / compliance webhooks.** If your app is distributed through the
Shopify App Store, it must be subscribed to Shopify's mandatory compliance topics.
You can create mandatory compliance webhook subscriptions either using your Partner
Dashboard or by updating your app configuration file. The compliance topics include
`customers/redact` (redact customer data) and `shop/redact` (redact shop data after
an app is uninstalled), delivered as sample payloads in the webhooks reference.
**Events (developer preview).** Events is Shopify's next-generation subscription
mechanism, currently in developer preview for a subset of topics. For supported
topics, Events and webhooks can run side by side in the same `shopify.app.toml`.
## When To Use
Use webhooks to stay in sync with Shopify or run code after an event: send
inventory-level change notifications, inform shipping companies about order/return/
refund changes, remove customer data on app uninstall, integrate order data with
accounting software, or update a product's warranty price when its price changes.
Compare with polling and see [[concepts/api-usage|API usage]].
## Risks & Pitfalls
- Shopify doesn't guarantee ordering within a topic or across topics for the same
resource (a `products/update` might arrive before `products/create`). Use the
`X-Shopify-Triggered-At` header or the payload `updated_at` to organize webhooks.
- Webhook delivery isn't always guaranteed; handlers can fail or go down.
Implement reconciliation jobs that periodically fetch data (many GraphQL queries
support `updated_at` filters) so your app stays consistent.
- App Store apps that skip mandatory compliance topics are non-compliant.
## Related Concepts
- [[concepts/building-apps|Building apps]]
- [[concepts/admin-graphql-api|Admin GraphQL API]]
- [[concepts/api-usage|API usage]]
- [[concepts/authentication-and-access|Authentication and access]]
## Sources
- raw/web_community-webhooks-md.md
- raw/web_community-webhooks-md-2.md
---
title: "What Is the Shopify Developer Platform"
type: concept
tags: [platform, apis, apps, themes, overview, foundational]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-api-md.md", "raw/web_community-build-md.md"]
confidence: high
---
## Definition
The Shopify developer platform (shopify.dev) is the set of APIs, libraries, tools, and UI extension surfaces that let developers build software on top of Shopify's commerce platform. As Shopify frames it: "Shopify is a commerce platform that apps extend. Build with APIs, web components, and backend logic to solve merchant problems across every surface." Developers build four broad kinds of things: apps (that read/write store data and extend Shopify's UI), custom storefronts (buyer-facing shopping experiences), themes (the online store's presentation layer), and integrations that react to store events. This page is the mental model that orients the rest of this knowledge base; it is for people building on Shopify, not for merchants running a store.
## How It Works
The platform is organized around a handful of API families and a set of "surfaces" your code can extend:
- **Data and logic APIs.** The [[concepts/admin-graphql-api|GraphQL Admin API]] is the primary interface for building apps that "extend and interact with the Shopify admin" -- products, customers, orders, inventory, and more. The [[concepts/admin-rest-api|REST Admin API]] is the legacy equivalent ("For new integrations, use the GraphQL Admin API instead"). The [[concepts/storefront-api|Storefront API]] powers "custom shopping experiences for web, mobile, gaming, and more." [[concepts/functions|Shopify Functions]] "customize backend logic for discounts, payments, and delivery." [[concepts/webhooks|Webhooks]] and Events let you "listen for store events and trigger your own logic."
- **UI extension surfaces (Polaris).** "All UI surfaces share Polaris, Shopify's unified system for building app interfaces." Your code "lives inside the Shopify experience": App Home, Admin UI extensions, Checkout UI extensions, Customer account UI extensions, and POS UI extensions.
- **Storefront surfaces.** Beyond the Storefront API, the platform includes [[concepts/liquid|Liquid]] (the theme template language), the [[concepts/hydrogen-and-headless|Hydrogen]] React framework, Hydrogen React, Storefront Web Components, and the Ajax API.
- **Extension model.** A single app can extend "multiple Shopify surfaces": App Home, Admin, Checkout, Customer accounts, Flow, Online store, Point of Sale, and Sidekick. See [[concepts/app-extensions]] and [[syntheses/app-surface-picker]].
Development starts with the [[concepts/shopify-cli|Shopify CLI]] ("Generate apps and extensions, run dev servers, and deploy projects"), the React Router app package ("Shopify's recommended package for building apps with React Router v7+"), and dev stores for testing. Cross-cutting concerns -- [[concepts/authentication-and-access|authentication]], versioning, and rate limits -- are documented under "About Shopify APIs" and covered in [[concepts/api-usage]].
## Key Parameters
- **API families:** GraphQL Admin API, REST Admin API (legacy), Storefront API, Customer Account API, Payments Apps API, Partner API, plus specialized APIs (ShopifyQL, Ajax, Customer Privacy, Multipass, Shop, Shop Minis).
- **Backend logic:** Shopify Functions, Webhooks, Events, Metafields, Metaobjects.
- **UI surfaces:** App Home, Admin UI extensions, Checkout UI extensions, Customer account UI extensions, POS UI extensions -- all built on Polaris.
- **Storefront tech:** Storefront API, Liquid, Hydrogen framework, Hydrogen React, Storefront Web Components, Ajax API.
- **Dev tooling:** Shopify CLI, React Router app package, Dev stores, Dev MCP server, Dev Dashboard, GraphiQL explorer, libraries for Ruby/Node/PHP/Go/.NET.
## When To Use
Use this page to decide which part of the platform a task belongs to:
- Reading or writing store data (products, orders, inventory) from a backend -> [[concepts/admin-graphql-api]].
- Building a buyer-facing storefront or headless commerce -> [[concepts/storefront-api]] and [[concepts/hydrogen-and-headless]].
- Adding UI inside the Shopify admin or checkout -> [[concepts/app-extensions]] and [[concepts/app-bridge]].
- Customizing backend business logic (discounts, delivery, payments) -> [[concepts/functions]].
- Reacting to store events -> [[concepts/webhooks]].
- Customizing a theme's presentation -> [[concepts/liquid]] and [[concepts/themes-architecture]].
## Risks & Pitfalls
- **Do not start new work on REST.** The REST Admin API is legacy as of October 1, 2024; since April 1, 2025 "all new public apps must be built exclusively with the GraphQL Admin API." Defaulting to REST out of habit will block App Store distribution. See [[concepts/admin-rest-api]].
- **Merchant vs developer scope confusion.** shopify.dev is the developer platform. Store operations documentation lives on help.shopify.com and is out of scope here.
- **Surface sprawl.** A single problem can often be solved on several surfaces; picking the wrong one (for example a script tag instead of a checkout UI extension) creates rework. Use [[syntheses/app-surface-picker]] to choose.
- **Polaris consistency requirement.** Shopify expects app UIs to render natively via Polaris; ignoring it risks App Store rejection under the "Integrating with Shopify" best practices.
## Related Concepts
- [[concepts/authentication-and-access]]
- [[concepts/admin-graphql-api]]
- [[concepts/storefront-api]]
- [[concepts/api-usage]]
- [[concepts/building-apps]]
- [[concepts/shopify-cli]]
- [[syntheses/admin-vs-storefront-api]]
- [[syntheses/app-surface-picker]]
## Sources
- raw/web_community-api-md.md (Shopify APIs, libraries, and tools -- https://shopify.dev/docs/api)
- raw/web_community-build-md.md (Build apps for Shopify -- https://shopify.dev/docs/apps/build)
---
title: "Activity Log"
type: log
---
# Activity Log
Append-only record of all wiki changes.
## Format
Each entry follows this format:
```
### YYYY-MM-DD HH:MM — [Action Type]
- **Source/Trigger**: what initiated the action
- **Pages created**: list of new pages
- **Pages updated**: list of updated pages
- **Notes**: any contradictions flagged, decisions made
```
---
### 2026-04-08 00:00 — Setup
- **Source/Trigger**: Repository initialized
- **Pages created**: index.md, log.md, dashboard.md, analytics.md, flashcards.md
- **Pages updated**: none
- **Notes**: Empty knowledge base ready for first source ingestion
---
title: "Admin API vs Storefront API"
type: synthesis
tags: [admin-api, storefront-api, authentication, graphql, decision-guide]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-admin-graphql-md.md", "raw/web_community-storefront-md.md", "raw/web_community-authentication-md.md", "raw/web_community-admin-rest-md.md", "raw/web_community-authentication-authorization-md.md", "raw/web_community-access-scopes-md.md"]
confidence: high
---
Shopify exposes store data through two very different APIs. The **Admin API**
manages a store on behalf of a *merchant/user* (create products, edit orders,
manage inventory). The **Storefront API** reads catalog data and runs a cart/
checkout on behalf of a *buyer/customer*. Choosing the wrong one leads to the
wrong auth model and either over-privileged tokens or missing capabilities.
## Comparison
| Dimension | Admin API | Storefront API |
| - | - | - |
| Acts on behalf of | The merchant/staff user (store management) | The buyer/customer (shopping) |
| Protocol | GraphQL (primary); REST is legacy | GraphQL only -- there is no REST storefront API |
| Endpoint | `https://{store}.myshopify.com/admin/api/2026-07/graphql.json` | `https://{store}.myshopify.com/api/2026-07/graphql.json` |
| Auth requirement | Always requires a token | Tokenless access OR token-based |
| Auth header | `X-Shopify-Access-Token` | `X-Shopify-Storefront-Access-Token` (public), `Shopify-Storefront-Private-Token` (private) |
| Scope type | Authenticated scopes (`read_products`, `write_orders`, ...) | Unauthenticated scopes (`unauthenticated_read_product_listings`, ...) |
| Token source | OAuth / token exchange / admin-generated | `storefrontAccessTokenCreate` mutation, Headless channel, or custom app |
| Reads | Full store: orders, customers, inventory, products, discounts, themes, payouts | Products, collections, search, pages/blogs, cart |
| Writes | Full store management (mutations across the whole admin) | Cart read/write and checkout only |
| Rate limit model | Calculated query cost (GraphQL); 40 req/min leaky bucket (REST) | Scales with real buyer traffic; bots throttled |
| Typical caller | Backend app server, embedded admin app | Browser, mobile app, headless storefront |
## Analysis
**Two auth philosophies.** Every Admin API request requires a valid token --
public and custom apps mint it via OAuth or token exchange, and admin-created
custom apps generate it in the Shopify admin. The token goes in the
`X-Shopify-Access-Token` header. The Storefront API is designed for public
exposure, so it supports **tokenless access** for the essentials: products and
collections, selling plans, search, pages/blogs/articles, and cart read/write.
A token is only required for a narrower set of features -- product tags,
metaobjects and metafields, the Online Store navigation menu, and customers.
**Public vs private storefront tokens.** Storefront token-based access splits in
two. **Public access tokens** (`X-Shopify-Storefront-Access-Token`) are safe to
ship in a browser or mobile app; capacity scales per buyer IP. **Private access
tokens** (`Shopify-Storefront-Private-Token`) are secrets for server-side
contexts like a Hydrogen backend and must never touch the client. When making
server-side Storefront requests tied to buyer traffic, also send the
`Shopify-Storefront-Buyer-IP` (case-sensitive) header so Shopify can enforce
per-buyer bot protection; omitting it risks throttling and degraded checkout.
**Scopes encode the "on behalf of" distinction.** The access-scopes model makes
the split explicit: *authenticated* scopes (like `read_products`,
`write_discounts`) control Admin API resources and mean "act on behalf of a
user"; *unauthenticated* scopes (like `unauthenticated_read_product_listings`,
`unauthenticated_write_checkouts`) control Storefront API objects and mean "act
on behalf of a customer." A third family, *customer* scopes
(`customer_read_orders`), belongs to the separate Customer Account API. Always
request the minimum -- Shopify restricts scope grants for apps that don't need
the data. See [[concepts/authentication-and-access|Authentication and access]].
**REST is winding down.** The REST Admin API became a legacy API on October 1,
2024, and since April 1, 2025 all *new public apps* must be built exclusively on
the [[concepts/admin-graphql-api|GraphQL Admin API]]. REST still works (40
requests per app/store/minute, replenishing at 2/sec, x10 for Plus) but new
platform features often ship GraphQL-only. Treat
[[concepts/admin-rest-api|Admin REST]] as maintenance-only.
**Rate limits differ by design.** The Admin GraphQL API charges a calculated
query cost against a bucket (max single-query cost 1000, restore 50 points/sec);
a too-large query returns a `200 OK` with a `MAX_COST_EXCEEDED` error. The
Storefront API instead scales with genuine buyer traffic and aggressively
throttles automated/bot traffic (a suspicious request gets `430 Shopify Security
Rejection`); tokenless access adds a per-query complexity cap of 1000. See
[[concepts/api-usage|API usage]].
**Storefront-only power tools.** The Storefront API adds `@inContext`
directives to contextualize any query by country, language, buyer identity, or
visitor consent, plus `@defer` for streaming partial responses -- capabilities
the Admin API doesn't need because it serves internal tooling, not shoppers.
## Recommendations
- **Pick the Admin API if** you are building an app or integration that manages
the store: creating/editing products, processing orders, adjusting inventory,
configuring discounts, or reading analytics. Use it from a trusted backend or
an embedded admin app -- never expose an admin token to a browser. Default to
GraphQL; only touch REST for legacy code. See [[concepts/building-apps|Building apps]].
- **Pick the Storefront API if** you are building a customer-facing buying
experience -- a headless storefront, a mobile shopping app, or an embedded
"buy" widget -- that shows products and drives a cart to checkout. Start with
tokenless access; add a public token only when you need tags, metafields,
menus, or customers.
- **Use both when** an app has a merchant-facing admin surface AND a custom
buyer storefront: the Admin API powers configuration and fulfillment, the
Storefront API powers the shopping UI. This is exactly the split a
[[syntheses/liquid-themes-vs-hydrogen|Hydrogen headless build]] relies on.
- **For buyer account data** (a logged-in customer viewing their own orders or
subscriptions), reach for the separate Customer Account API and its
`customer_*` scopes rather than stretching either API above.
## Pages Compared
- [[concepts/admin-graphql-api|Admin GraphQL API]]
- [[concepts/admin-rest-api|Admin REST API]]
- [[concepts/storefront-api|Storefront API]]
- [[concepts/authentication-and-access|Authentication and access]]
- [[concepts/api-usage|API usage]]
---
title: "App Surface Picker: Where Your App's Code Runs"
type: synthesis
tags: [functions, app-extensions, app-bridge, webhooks, checkout, admin, decision-guide]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-function-apis.md", "raw/web_community-app-extensions-md.md", "raw/web_community-app-bridge-md.md", "raw/web_community-admin-extensions-md.md", "raw/web_community-checkout-ui-extensions-md.md", "raw/web_community-webhooks-md.md"]
confidence: high
---
A Shopify app is rarely one program. Its code runs in several distinct places:
your own backend, Shopify's checkout sandbox, the admin iframe, WebAssembly on
Shopify's servers, and event handlers. Each surface has its own runtime,
language constraints, and purpose. Picking the right surface for a given need is
the core architecture decision when [[concepts/building-apps|building an app]].
## Comparison
| Surface | Runs where | Purpose | Language / runtime | Key limit |
| - | - | - | - | - |
| [[concepts/functions|Functions]] | Shopify's backend (WASM) | Customize checkout/commerce logic: discounts, delivery, validation, order routing | Any language compiling to Wasm; **Rust strongly preferred** | 256 kB binary, 11M instructions, no network by default, deterministic only |
| [[concepts/app-extensions|UI extensions (checkout)]] | Isolated sandbox in checkout | Custom fields, upsells, banners, Thank-you page UI | Preact + Polaris web components | 64 kB bundle; info/shipping/payment steps are Plus-only |
| UI extensions (admin) | Sandbox in Shopify admin | Blocks, action modals, print actions, Function settings on product/order/customer pages | Preact + web components | 64 kB bundle |
| [[concepts/app-bridge|App Bridge / App Home]] | Iframe in Shopify admin | Your app's main pages, settings, dashboards | Any JS framework + Polaris web components | Runs in an authenticated admin session |
| Theme app extensions | Online Store storefront | Add app blocks/UI to Liquid themes with no theme-code edits | Liquid + app block schema | Merchant places blocks via theme editor |
| [[concepts/webhooks|Webhooks]] | Your backend server | React to store events (orders/create, app/uninstalled) | Any HTTP server | Delivery not guaranteed; needs reconciliation |
## Analysis
**Functions = backend logic, no UI.** [[concepts/functions|Shopify Functions]]
inject custom business logic into the checkout/commerce loop -- new discount
types, delivery-option customization, cart and checkout validation, order
routing. They run as WebAssembly on Shopify's own infrastructure during key
purchase flows, so performance is non-negotiable: Rust is strongly recommended,
functions must be deterministic (no clocks, no randomness), and they can't print
to STDOUT/STDERR for debugging. A function has no interface of its own; when a
merchant needs to configure one, you pair it with an *admin UI extension* using
the `[extensions.ui]` block in `shopify.extension.toml`. Note the plan gating:
public App Store apps containing functions work on any plan, but *custom* apps
with functions require Shopify Plus.
**UI extensions = Shopify-hosted UI on Shopify's surfaces.** Both admin and
checkout UI extensions follow the same shape: *targets* say where the UI
appears, *target APIs* expose data through a global `shopify` object, and
*web components* render the interface. They run in an isolated sandbox (a Web
Worker), are capped at a 64 kB compressed bundle, and are built with Preact and
Polaris/remote-dom components. Admin UI extensions offer six target types --
Action, Selection action, Block, Configuration, Print action, and Runnable --
attaching to product/order/customer detail and index pages. Checkout UI
extensions offer Block, Runnable, and Static targets; extensions on the
information, shipping, and payment steps are **Shopify Plus only**. Use these
when your feature belongs *inside* a Shopify screen the merchant already uses.
**App Bridge / App Home = your app's home base.** When a merchant opens your
app, its landing page renders in **App Home**, an iframe in the Shopify admin.
[[concepts/app-bridge|App Bridge]] is the JavaScript SDK that lets that iframe
talk to the rest of the admin -- title bars, nav menus, toasts, modals -- and
authenticates automatically via the `shopify` global (session tokens via
`shopify.idToken()`). It also enables *direct API access*: querying the Admin
GraphQL API straight from front-end code with `fetch('shopify:admin/api/
graphql.json', ...)`. This is where your app's multi-page UI, dashboards, and
settings live. Extension-only apps can even skip a backend, hosting their main
page in App Home via an App Home UI extension.
**Theme app extensions = storefront UI without touching theme code.** To surface
app functionality on the Online Store itself (a review widget, a size chart), a
theme app extension lets merchants drop app blocks into their Liquid theme via
the theme editor -- no manual theme edits, and versioned with the rest of your
app. (Sourced from the general app-extensions guide; see
[[concepts/themes-architecture|themes architecture]] for how blocks fit a theme.)
**Webhooks = react to events, don't poll.** [[concepts/webhooks|Webhooks]] are
the event layer: subscribe to a topic (`orders/create`, `app/uninstalled`) in
`shopify.app.toml` or via the Admin API, and Shopify POSTs a payload to your
HTTPS endpoint, Google Pub/Sub, or EventBridge when the event fires. They are
the performant alternative to polling. But delivery isn't guaranteed and
ordering isn't either, so verify the HMAC signature, deduplicate on
`X-Shopify-Webhook-Id`, and run reconciliation jobs to backfill missed events.
## Recommendations
- **Pick Functions if** you need to change what Shopify *does* during checkout or
the commerce loop -- custom discounts, delivery/payment customization, cart
validation, order routing. Expect Rust, determinism, and tight resource caps.
- **Pick a checkout UI extension if** you need custom *visible* UI in checkout or
on the Thank-you page (fields, upsells, messaging). Remember info/shipping/
payment placements need Plus.
- **Pick an admin UI extension if** your feature should appear inside existing
admin pages -- an inline block on a product page, an action modal, a print
action, or a settings screen for a Function.
- **Pick App Bridge / App Home if** you need your app's own multi-page
interface, dashboard, or settings hub embedded in the admin.
- **Pick a theme app extension if** you need to add UI to the merchant's Online
Store storefront without editing their theme.
- **Pick webhooks if** you need to react to something that happened in the store
(sync data, notify a system, clean up on uninstall). Combine with a
reconciliation job for reliability.
Most real apps combine several: an App Home dashboard (App Bridge), a checkout
Function plus its admin-extension settings UI, and webhooks to stay in sync.
## Pages Compared
- [[concepts/functions|Functions]]
- [[concepts/app-extensions|App extensions]]
- [[concepts/app-bridge|App Bridge]]
- [[concepts/webhooks|Webhooks]]
- [[concepts/building-apps|Building apps]]
---
title: "Liquid Themes vs Hydrogen (Headless)"
type: synthesis
tags: [liquid, themes, hydrogen, headless, storefront, oxygen, decision-guide]
created: 2026-07-07
updated: 2026-07-07
sources: ["raw/web_community-liquid-md.md", "raw/web_community-architecture-md.md", "raw/web_community-hydrogen-md.md", "raw/web_community-headless-md.md", "raw/web_community-storefront-md.md"]
confidence: high
---
There are two fundamentally different ways to build a Shopify storefront. A
**classic Liquid theme** runs on Shopify's Online Store: Shopify hosts it,
renders it server-side, and merchants customize it in a visual editor. A
**Hydrogen headless** build is a React application you own end to end: it pulls
data from the [[concepts/storefront-api|Storefront API]], you deploy it (to
Oxygen or anywhere), and you control every pixel. The choice trades merchant
autonomy and speed-to-launch against developer control and flexibility.
## Comparison
| Dimension | Liquid theme (Online Store) | Hydrogen (headless) |
| - | - | - |
| Rendering | Server-rendered by Shopify | React SSR on React Router (you run it) |
| Language | Liquid template language + HTML/CSS/JS | React / JavaScript / TypeScript |
| Data source | Liquid objects populated by Shopify | Storefront API (+ Customer Account API) |
| Hosting | Shopify's Online Store (built in) | Oxygen (free edge) or bring-your-own host |
| Who customizes | Merchants, no-code, via theme editor | Developers, in code |
| Setup | Edit theme files; `theme.liquid` required | `npm create @shopify/hydrogen@latest` |
| Control over frontend | Constrained to theme architecture | Complete |
| Skill needed | Liquid + theme conventions | React + API integration |
| Distribution | Can sell in the Theme Store | N/A (bespoke storefront) |
| Best for | Standard stores, fast launch, merchant self-service | Custom UX, complex frontends, multi-channel |
## Analysis
**Liquid themes: Shopify does the heavy lifting.** [[concepts/liquid|Liquid]] is
Shopify's template language -- it hosts static markup and injects store data
(product image, title, price) at render time using `{{ output }}` objects,
`{% logic %}` tags, and `| filters`. A theme follows a fixed
[[concepts/themes-architecture|architecture]]: a **layout** (`theme.liquid`, the
only required file) wraps **templates**, which are composed of **sections** and
their **blocks**, with reusable **snippets**, plus `assets`, `config`,
`locales`. JSON templates act as wrappers that let merchants add, remove, and
reorder sections in the **theme editor** -- the source of Liquid's biggest
advantage: a merchant can restyle and rearrange the store with zero code. Dawn
is Shopify's reference theme, and Theme Check plus the Shopify CLI for themes
support local development. Because Shopify renders and hosts everything, there
is no infrastructure to run and no API integration to write.
**Hydrogen: a React framework for full control.** [[concepts/hydrogen-and-headless|Hydrogen]]
is Shopify's opinionated, React-based stack for headless commerce, built on
React Router. Instead of Liquid objects, it queries the Storefront API (and the
Customer Account API) through built-in, pre-wired clients and ships
"build-ready" components so you skip boilerplate. It's fast by default --
server-side rendering, progressive enhancement, nested routes -- and deploys to
**Oxygen**, Shopify's global edge host, which is free and includes continuous
deployment, push-to-preview, and instant rollbacks. You install the Hydrogen
sales channel (Oxygen included) or the Headless channel to host anywhere.
Versioning is tight: Hydrogen tracks Storefront API versions quarterly, so
`2023.10.x` pairs with Storefront API `2023-10`, and breaking API changes flow
into the matching Hydrogen release.
**Headless is broader than Hydrogen.** Hydrogen is the batteries-included path,
but "headless" just means decoupling the frontend from Shopify's rendering. You
can **bring your own stack** -- any language, any framework, any host -- and
install the Headless channel to create storefronts and manage Storefront API
tokens and permissions. For lightweight embedding, Storefront Web Components let
you sell products with a few lines of HTML. All of these lean on the Storefront
API's public/private token model (see [[syntheses/admin-vs-storefront-api|Admin
API vs Storefront API]]).
**The core trade-off.** Liquid optimizes for *merchant autonomy and time to
launch*: no hosting, no build pipeline, and a visual editor the merchant
operates alone -- at the cost of being confined to theme architecture and
Shopify's rendering. Hydrogen optimizes for *developer control*: arbitrary UX,
custom performance work, and integration with any data source or channel -- at
the cost of owning a codebase, an API integration, and (unless you take Oxygen's
defaults) deployment. Liquid needs Liquid fluency; Hydrogen needs a React team.
**They aren't mutually exclusive.** A merchant can run a standard Liquid Online
Store today and move to Hydrogen later, or run a headless storefront for the
main brand experience while keeping Shopify checkout. Both ultimately sell
through Shopify's commerce backend; only the frontend rendering model differs.
## Recommendations
- **Pick a Liquid theme if** you want a standard store live quickly, the merchant
should customize content and layout themselves without a developer, you don't
want to manage hosting or a build, or you plan to sell the theme in the Theme
Store. This is the right default for the large majority of stores.
- **Pick Hydrogen if** you need a bespoke frontend that theme architecture can't
express, want React and full control over routing/UX/performance, are building
a rich or app-like shopping experience, and have developers to own it. Take
Oxygen for free edge hosting with previews and rollbacks.
- **Pick bring-your-own-stack headless if** you must use a specific framework or
language, integrate an existing web app or CMS, or serve multiple channels
from one codebase -- and you accept full responsibility for hosting and the
Storefront API integration.
- **Avoid headless if** the team lacks frontend engineering capacity or the store
is straightforward: you'd trade Shopify's free rendering, hosting, and
merchant-editable theming for complexity you don't need.
## Pages Compared
- [[concepts/liquid|Liquid]]
- [[concepts/themes-architecture|Themes architecture]]
- [[concepts/hydrogen-and-headless|Hydrogen and headless]]
- [[concepts/storefront-api|Storefront API]]
- [[syntheses/admin-vs-storefront-api|Admin API vs Storefront API]]