Tip
experimental branch tracks Next Gen Dev Platform changes, see issue
Minimalist Shopify app using React Router (v7) running on cloudflare (worker, kv, analytics). Only essential features, no future changes other than core upgrades & platform alignment.
- @shopify/shopify-[api,app-remix] to complex (to much abstraction)
- Simple starter, than focusses on the basics
- Small code surface, easier audit
- Stability over features
- Modular, extendable, tree shakable (remove factory functions) -> smaller bundle size
- Minimally opinionated, by supporting only:
- Embedded app use-case
- New Embedded Auth Strategy
- Managed Pricing
- Optimized for Cloudflare stack
- Tested - (unit, browser, e2e)
Familiarity with React, ReactRouter, Cloudflare, Shopify conventions.
- Cloudflare account
- Shopify Partner account
- Node.js & NPM see package.json#engines
brew install node@22
- cloudflared cli
brew install cloudflared
(optional) - Github cli
brew install gh
(optional)
Note
For wss:// to work on a cloudflare tunnel, you need to set "Additional application settings" > "HTTP Settings" > "HTTP Host Header" to match the service URL (e.g. 127.0.0.1), otherwise the tunnel returns a 502 http status & client connection fails
Note
To bypass caching set: Caching > Cache Rules ["Rule Name" = "bypass cache on tunnel", "Custom filter expression" = "", Field = Hostname, Operator = equals, Value = tunnel url, "Cache eligibility" = "Bypass cache", "Browser TTL" = "Bypass cache" ]
npm install
cp .env.example .env # update vars to match your env values from partners.shopify.com (Apps > All Apps > Create App)
# vi [wrangler.json, shopify.app.toml] # update vars[SHOPIFY_API_KEY, SHOPIFY_APP_URL], SHOPIFY_APP_URL is the cloudflare tunnel url (e.g. https://shopflare.trycloudflare.com) in development and the cloudflare worker url (e.g. https://shopflare.workers.dev) in other environments.
npx wrangler secret put SHOPIFY_API_SECRET_KEY
npx wrangler kv namespace create shopflare # update wranglers.json#kv_namespaces[0].id
gh secret set --app=actions CLOUDFLARE_API_TOKEN # value from dash.cloudflare.com (Manage Account > Account API Tokens > Create Token)
gh secret set --app=actions SHOPIFY_CLI_PARTNERS_TOKEN # value from partners.shopify.com (Settings > CLI Token > Manage Tokens > Generate Token)
gh variable set SHOPIFY_API_KEY
# vi .env # update vars[SHOPIFY_APP_LOG_LEVEL] sets logging verbosity.
npm run deploy:shopify # only required on setup or config changes
npm run gen
npm run dev # or npm run dev:shopify:tunnel
# open -a Safari ${SHOPIFY_APP_URL}
npm run build
npm run deploy
To split environments see Cloudflare and Shopify docs.
export async function loader({ context, request }) {
const shopify = createShopify(context);
shopify.utils.log.debug("message..."); // Log on [error, info, debug]
const client = await shopify.admin(request); // Authenticate on [admin*, proxy*, webhook] [*] returns a client
const { data, errors } = await client.request(`query { shop { name } }`);
shopify.redirect(request, url, { shop });
shopify.session.get(sessionId); // [get, set, delete, clear](id = shop)
shopify.utils.addCorsHeaders(request, responseHeaders); // handle CORS headers
}
const admin = createShopifyClient({ headers: { "X-Shopify-Access-Token": "?" }, shop });
const storefront = createShopifyClient({ headers: { "X-Shopify-Storefront-Access-Token": "?" }, shop });
Follow Shopify App Proxy docs but import from ~/components/proxy
instead of @shopify/shopify-app-remix/react
issue/#
references an current issue / pull-requestextension/#
is a non core feature extension
Copyright (c) 2025 chr33s. See LICENSE.md for further details.