Introduction
Shopify’s ecosystem empowers merchants with extensible storefronts, admin interfaces, and integrations via custom apps. The Shopify CLI streamlines app creation, authentication, and deployment, while Node.js offers a performant, JavaScript-first backend. In this comprehensive tutorial, you’ll learn how to scaffold a Shopify custom app, implement OAuth authentication, subscribe to webhooks, add REST and GraphQL endpoints, and deploy your app—using modern Node.js frameworks and the Shopify App CLI. By the end, you’ll have a robust foundation to build features like product synchronization, order automation, and embedded admin UI components.

Prerequisites
Before you begin, ensure you have:
- Shopify Partner account (create at partners.shopify.com)
- Node.js v14+ and npm installed
- Git command-line tools
- ngrok or similar tunneling tool for local HTTPS development
- Basic familiarity with JavaScript/TypeScript and Express or Koa
1. Install Shopify CLI and Create Your App
2. Configure App Credentials
- Create App in Partner Dashboard
- In your Partner account, go to Apps → Create app → Custom app
- Set the App URL and Allowed redirection URL(s) to your ngrok URL, e.g.,
https://abcd1234.ngrok.io/api/auth/callback
- Add API Key & Secret to
.env
envCopyEditSHOPIFY_API_KEY=your_api_key SHOPIFY_API_SECRET=your_api_secret SCOPES=read_products,write_orders HOST=https://abcd1234.ngrok.io
- Restart your dev server bashCopyEdit
npm run dev
3. Implement OAuth Authentication
The CLI template uses @shopify/koa-shopify-auth
. In Express, you’ll use @shopify/shopify-express
or passport-based flow:
- Initialize OAuth middleware jsCopyEdit
import shopifyAuth, { verifyRequest } from '@shopify/shopify-express'; app.use( shopifyAuth({ apiKey: process.env.SHOPIFY_API_KEY, secret: process.env.SHOPIFY_API_SECRET, scopes: process.env.SCOPES.split(','), afterAuth(ctx) { const { shop, accessToken } = ctx.state.shopify; // Save to session or database ctx.redirect('/'); }, }), );
- Protect routes jsCopyEdit
app.get('/api/products', verifyRequest(), async (req, res) => { const session = await Shopify.Utils.loadCurrentSession(req, res); const client = new Shopify.Clients.Rest(session.shop, session.accessToken); const products = await client.get({ path: 'products' }); res.json(products); });
4. Building REST and GraphQL Endpoints
4.1 REST Example: Fetch Products
jsCopyEditapp.get('/api/products', verifyRequest(), async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(req, res);
const client = new Shopify.Clients.Rest(session.shop, session.accessToken);
const response = await client.get({ path: 'products', query: { limit: 10 } });
res.json(response.body.products);
});
4.2 GraphQL Example: Query Orders
jsCopyEditimport { Shopify } from '@shopify/shopify-api';
app.post('/api/graphql', verifyRequest(), async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(req, res);
const client = new Shopify.Clients.Graphql(session.shop, session.accessToken);
const data = await client.query({
data: `{
orders(first:5) {
edges { node { id name totalPriceSet { shopMoney { amount currencyCode } } } }
}
}`,
});
res.json(data.body.data.orders);
});
5. Subscribing to Webhooks
Webhooks let your app respond to store events (e.g., new orders):

- Register webhook on install jsCopyEdit
import { registerWebhook } from '@shopify/koa-shopify-webhooks'; await registerWebhook({ address: `${HOST}/webhooks/orders/create`, topic: 'ORDERS_CREATE', accessToken, shop, });
- Handle incoming webhooks jsCopyEdit
app.post('/webhooks/orders/create', koaBody(), async (ctx) => { const order = ctx.request.body; // Process order: fulfillment, notifications, etc. console.log(`New order: ${order.id}`); ctx.res.statusCode = 200; });
6. Adding Embedded App UI with Polaris
- Install Polaris bashCopyEdit
cd web npm install @shopify/polaris @shopify/app-bridge-react
- Wrap your App in AppProvider jsxCopyEdit
import { AppProvider } from '@shopify/polaris'; import { Provider as AppBridgeProvider } from '@shopify/app-bridge-react'; function MyApp({ Component, pageProps }) { const config = { apiKey: process.env.SHOPIFY_API_KEY, shopOrigin: shopOrigin }; return ( <AppBridgeProvider config={config}> <AppProvider i18n={{}}> <Component {...pageProps} /> </AppProvider> </AppBridgeProvider> ); }
- Build a Dashboard Page jsxCopyEdit
import { Card, Page, DataTable } from '@shopify/polaris'; function Dashboard({ products }) { const rows = products.map(p => [p.id, p.title, p.vendor]); return ( <Page title="Products"> <Card> <DataTable columnContentTypes={['text','text','text']} headings={['ID','Title','Vendor']} rows={rows} /> </Card> </Page> ); }
- Fetch data via API
IngetServerSideProps
, call your/api/products
endpoint to populate the dashboard.
7. Billing and Subscriptions
If you plan to monetize your app, use the Shopify Billing API:
- Create a one-time charge jsCopyEdit
const billingResponse = await Shopify.Billing.Invoices.create({ session, lineItems: [{ name: 'Pro Plan', quantity: 1, unitPrice: '20.00' }], test: true, }); ctx.redirect(billingResponse.invoice.paymentUrl);
- Verify payment before activating features.
8. Testing and Deployment
- Local testing with ngrok bashCopyEdit
ngrok http 3000
Update your app’s URLs in the Partner Dashboard. - Automated tests
- Use Jest and Supertest for your server endpoints.
- Cypress for end-to-end UI flows within the embedded app.
- Deploy to production
- Push code to a repository (GitHub, GitLab).
- Use CI/CD pipelines to build and deploy to Heroku, Vercel, or your preferred host.
- Secure environment variables (API keys, secrets) via your platform’s secrets manager.

Conclusion
Building a custom Shopify app with the CLI and Node.js gives you the power to extend merchant stores with tailored functionality—whether automating order workflows, integrating third-party services, or adding rich embedded UIs. By following this guide, you’ve learned how to scaffold your app, authenticate via OAuth, expose REST and GraphQL endpoints, handle webhooks, create a polished Polaris-based admin interface, and deploy your solution. From here, explore deeper features—script tags, theme extensions, and Admin UI extensions—to create differentiated, high-value Shopify apps. Happy coding!