How to create a Shopify app: a practical walkthrough
From an empty folder to an app installed on a development store, doing something useful — the actual sequence.
9 min read · Apps & checkout ·
This is the practical sequence for creating a Shopify app: from an empty folder to something installed on a development store doing real work. It assumes you can run Node and have a Shopify Partner account, which is free.
1. Scaffold
``bash npm init @shopify/app@latest cd your-app npm run dev ``
The CLI asks a few questions, creates a Remix app, registers it against your Partner account, and starts a dev server with a tunnel so Shopify can reach your local machine. The first dev run also prints an install link.
If you'd rather not use Remix, you don't have to — but do read what the template gives you before rejecting it, because the parts it handles are the parts that are fiddly.
2. Create a development store
From your Partner dashboard. Development stores are free, can't take real orders, and are where you install the app while building. Populate one with realistic data — a handful of products, a few orders, a customer or two. Testing against an empty store is how you ship an app that breaks on day one with a real catalogue.
3. Install it
Open the install link the CLI printed, choose your development store, and approve the scopes. The app now appears in that store's admin, embedded in an iframe, running from your laptop through the tunnel.
4. Request the right scopes
Scopes are declared in shopify.app.toml:
``toml [access_scopes] scopes = "read_products,write_products,read_orders" ``
Two rules. Ask for the minimum — merchants see the list at install and an app asking to read customer data for no visible reason loses installs. And know that changing scopes requires reinstallation, which for a live app means every merchant re-approving. Work out what you need before you distribute.
More on this in authentication and OAuth.
5. Your first API call
In a Remix loader, the template gives you an authenticated client:
``js export async function loader({ request }) { const { admin } = await authenticate.admin(request); const response = await admin.graphql( query { products(first: 10) { edges { node { id title totalInventory } } } } ); const { data } = await response.json(); return json({ products: data.products.edges }); } ``
Note it's GraphQL, and note the first: 10 — everything in the Admin API is paginated, and pagination plus rate limits shape how you write anything that touches the whole catalogue. The Admin API guide covers both.
6. Build the admin UI
Render with Polaris, Shopify's design system, so your app looks like part of the admin rather than a website in an iframe. Merchants trust it more and you get accessible components without building them.
Keep the first screen useful. Apps that open on a settings form nobody understands get uninstalled; apps that open showing something true about the merchant's store get used.
7. Handle webhooks
Register for the events you care about, plus the mandatory privacy webhooks every app must implement:
``toml [[webhooks.subscriptions]] topics = ["orders/create"] uri = "/webhooks" ``
Verify the HMAC on every incoming request, respond fast, and process asynchronously. And make handlers idempotent — Shopify delivers at least once, so the same order will arrive twice eventually. Webhooks covers doing this properly.
8. Add an extension
An app that only lives on its own admin page is easy to forget. Extensions put it where work happens:
``bash npm run shopify app generate extension ``
Pick based on where the value is: admin UI extensions for the order or product page, theme app extensions for the storefront, Functions for checkout logic.
9. Deploy
The app needs hosting — anywhere that runs Node and gives you a stable HTTPS URL. Then:
``bash npm run deploy ``
which pushes your app configuration and extension versions to Shopify. Update the app URLs in the Partner dashboard to point at production rather than the tunnel.
10. Distribute
For a single client, generate an install link and you're done. For the App Store, you're now starting a separate process with its own requirements — listing requirements — and a different commercial model, covered in private vs public.
The things that bite first
- Testing against an empty store. Load real-ish data on day one.
- Forgetting pagination. Works with 10 products, times out with 10,000.
- Ignoring rate limits until the app fails on a large catalogue.
- Non-idempotent webhook handlers, which produce duplicate records the first time a delivery retries.
- Building settings before building value. Ship the thing that does the work first.
Getting an app installed and querying data takes an afternoon. Making it reliable against a real store's data volume is the actual project.
Is this the problem you’re looking at?
Send me the link to your store and a line about what is going wrong. You get a straight answer within one business day — no pitch, no obligation.
mario@clicksandcarts.coOr see what I do around Shopify: services, work beyond the theme, selected work.