The API
2. Deploy to Netlify
Generate the folder, create the site, set the variables.
The second half. This produces the URL your App Proxy will point at.
Netlify is the documented path and the one that ships configured. If you'd rather host this elsewhere, the requirements are small and the setup shape is identical — see Other platforms.
What actually gets deployed
Not the theme. npm run api:build writes a folder that has nothing to do with
your storefront:
deploy/netlify/├── netlify.toml config├── package.json no dependencies, on purpose├── public/.gitkeep an empty folder Netlify insists on└── netlify/functions/ ├── admin-gql.mjs → POST /admin.gql ├── service.mjs → POST /service └── _src/ the handler code, copied inIt is self-contained. Nothing in it imports back into the theme, so it can be deployed on its own, committed to its own repo, or dragged into a dashboard.
Two things about it surprise people, and both are correct:
- There is no build step. The functions are plain JavaScript, already
runnable.
netlify.tomldeclares a no-op build command on purpose. - The published site is empty. This is an API, not a website. Netlify requires a publish directory, so it gets one with nothing in it.
1. Generate the folder
npm run api:buildRun this from the theme root, not from deploy/. It prints the routes it made
and the access scopes your operations need — keep that output, you'll want the
scopes in a minute.
2. Create the Netlify site
cd deploy/netlifynpx netlify loginnpx netlify initnetlify init asks a few questions. The answers that matter:
- "What would you like to do?" → Create & configure a new project
- Team → whichever you use
- Project name → anything, or leave blank for a generated one. This becomes
your URL, so
acme-store-apibeatsstalwart-tulumba-a58f6c.
If it offers to set a build command, it guessed wrong — say no, or ignore it. Netlify's framework detection walks up out of this folder, finds the theme's Vite setup, and suggests something like
remix vite:build. That fails withremix: command not found, because none of that is installed here.
netlify.tomlstates the real command explicitly, and file config beats anything saved in the UI — so even if a wrong guess got saved, the next deploy overrides it.
3. Deploy
npx netlify deploy --prodYou'll see it bundle two functions and upload one file. That one file is the
.gitkeep. Correct.
Note the URL it prints — something like https://acme-store-api.netlify.app.
That is what goes in your App Proxy.
4. Set the environment variables
Three of them. These are what make the API work, and it will fail closed without them.
npx netlify env:set SHOPIFY_SHOP your-store.myshopify.comnpx netlify env:set SHOPIFY_CLIENT_ID your_client_idnpx netlify env:set SHOPIFY_API_SECRET your_client_secret| Variable | Where it comes from |
|---|---|
SHOPIFY_SHOP | Your .myshopify.com domain — not a custom domain |
SHOPIFY_CLIENT_ID | client_id in shopify.app.toml |
SHOPIFY_API_SECRET | The Client secret from the Dev Dashboard |
Then deploy again:
npx netlify deploy --prodThis is not optional. A Netlify deploy captures the environment as it was at deploy time, so variables set after a deploy are invisible to the functions until a new one goes out.
The dashboard equivalent is Site configuration → Environment variables.
Never set
SHOPIFY_ALLOW_RAW_GQLhere. It makes the endpoint accept arbitrary GraphQL from anyone who can reach it, which on a storefront means everyone.
5. Check it responded
curl -i -X POST 'https://your-site.netlify.app/admin.gql' \ -H 'Content-Type: application/json' \ -d '{"operation":"GetShop"}'You want a 401.
| Response | Meaning |
|---|---|
401 Invalid signature | ✅ Working. The endpoint is up and refusing unsigned traffic |
500 Server is not configured | SHOPIFY_API_SECRET isn't set, or you didn't redeploy after setting it |
404 | Wrong path. The routes are /admin.gql and /service at the site root |
A 401 looks like failure and is the healthy answer. Your storefront's requests
arrive through the App Proxy with a signature attached; a raw curl has none, so
it is correctly rejected.
Where the functions are in the dashboard
Under the Functions tab, not in the deploy's file browser. The file browser
shows the published folder, which is empty apart from netlify.toml — that is
expected and not a sign anything went wrong.
Redeploying later
Operations and services are compiled into this folder at build time. Adding a
.graphql file to the theme does nothing in production until you rebuild and
redeploy:
npm run api:buildcd deploy/netlify && npx netlify deploy --prodapi:build regenerates the files but leaves .netlify/ alone, so the folder
stays linked to your site. You run netlify init once, ever.
Next
Wire the two halves together → Connect them