Skip to main content
Innovatrix Infotech — home
Shopify

How to Build a Custom Shopify App: Step-by-Step for Developers in 2026

A no-nonsense guide to building your first Shopify app in 2026 — covering both public and custom (private) apps, Shopify CLI setup, App Bridge, webhooks, rate limits, and when to build vs. buy from the App Store.

Photo of Rishabh SethiaRishabh SethiaFounder & CEO11 February 2026Updated 26 March 202616 min read1.6k words
#shopify#shopify app development#shopify CLI#custom app#webhooks#shopify API#developer tutorial#node.js

How to Build a Custom Shopify App: Step-by-Step for Developers in 2026

Most Shopify app tutorials teach you how to build a public app for the Shopify App Store. That's useful if you want to build a SaaS product — but most agencies and in-house teams need custom apps: private apps built for a single store that solve a specific business problem.

This guide covers both. Whether you're a developer who knows JavaScript/Node.js but has never touched Shopify, or an ecommerce operator evaluating whether to build or buy — this is the walkthrough we wish existed when we started building Shopify solutions.

Public vs. Custom Apps: The Distinction That Changes Everything

Public apps are listed on the Shopify App Store. They go through Shopify's review process, need to handle multi-tenant authentication, and can be installed by any merchant. Revenue comes from app subscriptions via Shopify's Billing API.

Custom apps (formerly "private apps") are built for one specific store. They're created directly in the store's admin under Settings > Apps and sales channels > Develop apps. No review process, no App Store listing, no multi-tenant complexity.

When to build custom:

  • Your store needs functionality no existing app provides
  • You want full control over data flow and no third-party dependency
  • The logic is specific to your business (custom order tagging, vendor-specific workflows, bespoke reporting)
  • You need to integrate Shopify with internal systems (ERP, custom CRM, warehouse management)

When to buy from the App Store:

  • The functionality is commodity (reviews, email popups, countdown timers)
  • Multiple apps compete in the space (competition drives quality)
  • The total cost of ownership for building exceeds 12 months of app subscription fees
  • You don't have a developer or agency on retainer

Setting Up Your Development Environment

Prerequisites

  • Node.js 18+ (LTS recommended)
  • npm or yarn
  • A Shopify Partner account (free at partners.shopify.com)
  • A development store (create one from your Partner dashboard)

Step 1: Install Shopify CLI

npm install -g @shopify/cli @shopify/app

Verify the installation:

shopify version

You should see version 3.x or later. The CLI handles app scaffolding, local development tunneling, and deployment.

Step 2: Scaffold Your App

shopify app init

The CLI will prompt you to choose:

  1. App template: Choose the Remix template (Shopify's recommended framework since 2024) or the Node.js template if you prefer Express-style architecture.
  2. Language: TypeScript is recommended for anything beyond a weekend project.
  3. App name: Something descriptive — you can change this later.

This creates a project with:

  • OAuth authentication flow (already configured)
  • App Bridge integration (for embedding in Shopify admin)
  • Prisma ORM for database operations
  • A basic admin UI using Polaris components

Step 3: Start Local Development

cd your-app-name
shopify app dev

This spins up a local server, creates a secure tunnel (via Cloudflare), and opens your development store with the app installed. Every code change hot-reloads.

Building a Real App: The Order Tagger

Let's build something practical: an app that automatically tags orders based on custom rules. For example, tag orders over ₹5,000 as "high-value," tag orders containing specific products as "gift-bundle," and tag repeat customers' orders as "returning."

This is a common need that most store owners solve with Shopify Flow (if they're on Plus) or with paid apps. Building it custom gives you full control.

Step 4: Register Webhooks

Webhooks are how Shopify tells your app that something happened. For order tagging, you need the orders/create webhook.

In your app's webhook configuration (typically shopify.app.toml):

[webhooks]
api_version = "2026-01"

  [[webhooks.subscriptions]]
  topics = ["orders/create"]
  uri = "/webhooks/orders-create"

Step 5: Handle the Webhook

Create a webhook handler that processes incoming orders:

// app/routes/webhooks.orders-create.tsx
import type { ActionFunction } from '@remix-run/node'
import { authenticate } from '../shopify.server'

export const action: ActionFunction = async ({ request }) => {
  const { topic, shop, payload } = await authenticate.webhook(request)

  const order = payload
  const tags: string[] = []

  // Rule 1: High-value orders
  if (parseFloat(order.total_price) > 5000) {
    tags.push('high-value')
  }

  // Rule 2: Repeat customer
  if (order.customer?.orders_count > 1) {
    tags.push('returning-customer')
  }

  // Rule 3: Gift bundle detection
  const hasGiftProduct = order.line_items?.some(
    (item: any) => item.product_id === YOUR_GIFT_PRODUCT_ID
  )
  if (hasGiftProduct) {
    tags.push('gift-bundle')
  }

  // Apply tags via GraphQL
  if (tags.length > 0) {
    const client = new shopify.clients.Graphql({ session })
    await client.query({
      data: {
        query: `mutation orderUpdate($input: OrderInput!) {
          orderUpdate(input: $input) {
            order { id tags }
            userErrors { field message }
          }
        }`,
        variables: {
          input: {
            id: `gid://shopify/Order/${order.id}`,
            tags: tags
          }
        }
      }
    })
  }

  return new Response('OK', { status: 200 })
}

Step 6: Handle Rate Limits

Shopify's API uses a leaky bucket algorithm for rate limiting. For REST, you get 40 requests per app per store, replenishing at 2 per second. For GraphQL, it's a cost-based system with 1,000 points, replenishing at 50 per second.

In production, implement retry logic:

async function shopifyRequest(fn: () => Promise<any>, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn()
    } catch (error: any) {
      if (error.response?.code === 429) {
        const retryAfter = parseFloat(
          error.response.headers['retry-after'] || '2'
        )
        await new Promise(resolve =>
          setTimeout(resolve, retryAfter * 1000)
        )
        continue
      }
      throw error
    }
  }
  throw new Error('Max retries exceeded')
}

For bulk operations (syncing hundreds of products, processing historical orders), use Shopify's Bulk Operations API instead of paginated queries. It runs asynchronously and doesn't count against rate limits.

Metafields vs. Metaobjects: Custom Data Storage

Metafields attach key-value data to existing Shopify resources (products, orders, customers). Use them for simple data like cost-per-unit, vendor tags, or custom attributes.

mutation {
  metafieldsSet(metafields: [
    {
      ownerId: "gid://shopify/Product/123456789"
      namespace: "custom"
      key: "cost_per_unit"
      value: "450.00"
      type: "number_decimal"
    }
  ]) {
    metafields { id key value }
    userErrors { field message }
  }
}

Metaobjects are standalone data entities with their own schema. Use them when you need structured data that doesn't naturally belong to a product or order — vendor profiles, custom lookup tables, configuration objects.

The rule of thumb: if the data describes something that already exists in Shopify (a product, a customer), use Metafields. If it's a new concept your store needs to track, use Metaobjects.

App Bridge: Embedding in Shopify Admin

App Bridge 3 lets your app render inside the Shopify admin as a seamless embedded experience. The Remix template includes this by default, but understanding the key concepts helps:

Navigation: Your app gets a left-nav item in the Shopify admin. Each route in your Remix app maps to a page within that navigation.

Session tokens: App Bridge handles authentication via session tokens instead of cookies. This means your app works in the embedded iframe without third-party cookie issues.

Polaris components: Shopify's design system. Using Polaris ensures your app looks native and follows Shopify's UX patterns. Don't fight it — merchants expect consistency.

The Billing API: Charging Merchants

If you're building a public app, Shopify takes a revenue share (currently 0% for the first $1M in annual revenue, then 15%). You charge merchants through the Billing API:

mutation {
  appSubscriptionCreate(
    name: "Pro Plan"
    returnUrl: "https://your-app.com/billing/callback"
    lineItems: [
      {
        plan: {
          appRecurringPricingDetails: {
            price: { amount: 29.99, currencyCode: USD }
            interval: EVERY_30_DAYS
          }
        }
      }
    ]
  ) {
    appSubscription { id }
    confirmationUrl
    userErrors { field message }
  }
}

For custom apps, billing is handled directly between you and your client — no Shopify involvement.

Hosting Your App in Production

For custom apps serving a single store, hosting requirements are modest:

AWS Lambda + API Gateway: Serverless, pay-per-invocation. Ideal for webhook-driven apps like our Order Tagger. As an AWS Partner, this is our default recommendation for lightweight custom apps. Cold starts can add 1–2 seconds to the first request, but for webhook processing this is rarely noticeable.

AWS App Runner: Container-based, always-warm. Better for apps with admin UIs that merchants interact with regularly. Starts at ~$5/month for a minimal instance.

Heroku or Railway: Simpler deployment, higher per-unit cost. Good for prototyping, less ideal for production apps that need to scale.

Vercel: If you chose the Remix template, Vercel deployment is nearly zero-config. The free tier handles most custom apps comfortably.

Build vs. Buy: Total Cost of Ownership

Before building anything, run this calculation:

Build cost:

  • Development time × developer rate (20–80 hours for a simple app)
  • Hosting cost per month ($5–$50)
  • Maintenance time per month (2–5 hours for updates, Shopify API version bumps)

Buy cost:

  • App subscription × 12 months
  • Customization limitations (workarounds, manual processes)
  • Data dependency (what happens if the app shuts down?)

If building costs less than 18 months of subscription fees AND gives you meaningfully better functionality, build. Otherwise, buy.

For most stores, the breakeven point is around $150–$200/month in app subscription costs. Below that, buying is almost always more efficient. Above that — especially if you're paying for multiple apps that a single custom app could replace — building starts making sense.

What's Next

Once you've built your first custom app, the natural extension is connecting it with your broader web development stack. Custom apps become the glue between Shopify and your internal systems — syncing inventory with your warehouse, pushing order data to your accounting software, or triggering custom workflows that no off-the-shelf app supports.

If you're evaluating whether to build or buy for your specific use case, book a discovery call. We'll scope the project honestly and tell you if a $15/month app store solution does the job better.


Building a custom Shopify app and need architecture guidance? Talk to our team — we've built custom apps for stores across India, Dubai, and Singapore.

Written by

Photo of Rishabh Sethia
Rishabh Sethia

Founder & CEO

Rishabh Sethia is the founder and CEO of Innovatrix Infotech, a Kolkata-based digital engineering agency. He leads a team that delivers web development, mobile apps, Shopify stores, and AI automation for startups and SMBs across India and beyond.

Connect on LinkedIn
Get started

Ready to talk about your project?

Whether you have a clear brief or an idea on a napkin, we'd love to hear from you. Most projects start with a 30-minute call — no pressure, no sales pitch.

No upfront commitmentResponse within 24 hoursFixed-price quotes