Entwicklung

Shopify App entwickeln: Eine ehrliche Anleitung 2025

18 min LesezeitJustin Kreutzmann
Shopify App entwickeln - Eine ehrliche Anleitung

Warum überhaupt eine Custom Shopify App?

Sie haben ein etabliertes Shopify-Setup, aber stoßen an Grenzen: Standard-Apps decken Ihre spezifischen Workflows nicht ab, externe Systeme müssen angebunden werden, oder Sie brauchen eine Business-Logik, die kein Plugin bietet.

Das ist der Moment, wo eine Custom Shopify App die richtige Lösung ist.

In diesem umfassenden Guide erkläre ich aus 10+ Jahren E-Commerce-Entwicklung:

  • Wann lohnt sich eine Custom App wirklich?
  • Private App vs. Public App: Was brauchen Sie?
  • Technischer Stack und Architektur-Entscheidungen
  • Moderne Best Practices für 2025
  • Realistische Kosten und Entwicklungszeit
  • Häufige Fehler und wie Sie sie vermeiden
  • Testing, Deployment und Monitoring-Strategien

Private App vs. Public App: Der entscheidende Unterschied

Private Apps (Custom Apps)

Wann Sie eine Private App brauchen:

  • Individuelle Business-Logik für Ihren Shop
  • Integration mit internen Systemen (ERP, CRM, Warenwirtschaft)
  • Custom Workflows, die nur Sie nutzen
  • Keine Absicht, die App an andere Händler zu verkaufen
  • B2B-spezifische Funktionen (Netto-Preise, Kundengruppen)

Vorteile:

  • ✅ Schnellere Entwicklung (kein App-Store-Review)
  • ✅ Volle Kontrolle über Daten und Hosting
  • ✅ Keine Vorgaben von Shopify (außer API-Limits)
  • ✅ Günstiger in Entwicklung und Betrieb
  • ✅ Direkte API-Token-Authentifizierung (einfacher)

Technischer Aufwand: 2-8 Wochen (je nach Komplexität) Kosten: €3.000 - €15.000 (einmalig)

Public Apps (App Store Apps)

Wann Sie eine Public App brauchen:

  • Sie wollen Ihre Lösung an andere Shopify-Händler verkaufen
  • Recurring Revenue durch Abo-Modell
  • Skalierbare SaaS-Lösung

Vorteile:

  • ✅ Potenzial für passives Einkommen
  • ✅ Große Reichweite (Millionen Shopify-Händler)
  • ✅ Shopify kümmert sich um Billing
  • ✅ Automatische Distribution und Updates

Herausforderungen:

  • ❌ Strenger App-Store-Review-Prozess (2-4 Wochen Review-Zeit)
  • ❌ Höhere Qualitätsanforderungen (UX, Performance, Support)
  • ❌ Shopify behält 15-20% Revenue-Share
  • ❌ Deutlich höherer Entwicklungs- und Wartungsaufwand
  • ❌ GDPR/CCPA-Compliance zwingend erforderlich
  • ❌ Multi-Tenant-Architektur notwendig

Technischer Aufwand: 3-6 Monate (MVP) Kosten: €18.000 - €60.000+ (initialer Launch)

Der technische Stack: Was Sie wirklich brauchen

1. Backend-Technologie

Empfehlung: Node.js + Express/Fastify

Shopify Webhook Handler mit Verificationjavascript
// server.js - Express Backend mit Webhook-Handling
import express from 'express';
import crypto from 'crypto';
import { Shopify } from '@shopify/shopify-api';

const app = express();

// WICHTIG: Raw body für HMAC-Verifizierung
app.post('/webhooks/orders/create',
express.raw({ type: 'application/json' }),
async (req, res) => {
  const hmac = req.headers['x-shopify-hmac-sha256'];
  const shop = req.headers['x-shopify-shop-domain'];

  // HMAC-Verifizierung (Security-kritisch!)
  const verified = verifyShopifyWebhook(req.body, hmac);

  if (!verified) {
    console.error('Webhook verification failed');
    return res.status(401).send('Unauthorized');
  }

  // Webhook-Verarbeitung in Queue verschieben
  // NIEMALS synchron verarbeiten (Timeout-Gefahr!)
  try {
    await queueJob('process-order', {
      shop,
      order: JSON.parse(req.body)
    });

    // Schnell antworten (< 5 Sekunden!)
    res.status(200).send('OK');
  } catch (error) {
    console.error('Queue error:', error);
    res.status(500).send('Internal Error');
  }
});

// HMAC-Verifizierung
function verifyShopifyWebhook(body, hmacHeader) {
const hash = crypto
  .createHmac('sha256', process.env.SHOPIFY_WEBHOOK_SECRET)
  .update(body, 'utf8')
  .digest('base64');
return hash === hmacHeader;
}

// Background Job Processing (BullMQ/Redis)
async function queueJob(jobName, data) {
// Implementierung mit BullMQ oder ähnlich
await orderQueue.add(jobName, data, {
  attempts: 3,
  backoff: {
    type: 'exponential',
    delay: 2000
  }
});
}

Warum Node.js?

  • Offiziell von Shopify unterstützt (@shopify/shopify-api npm package)
  • Beste Dokumentation und Community
  • Schnelle Entwicklung durch JavaScript/TypeScript
  • Große Auswahl an Libraries für Integration
  • Async/Await perfekt für API-Calls

Alternativen:

  • Ruby (Rails): Traditionelle Wahl, gute Shopify-Gems
  • Python (Django/Flask): Gut für ML/AI-Integration
  • PHP (Laravel): Viele PHP-Entwickler verfügbar
  • Go: Sehr performant, gut für High-Traffic-Apps

2. Frontend (für Embedded Apps)

Empfehlung: React + Shopify Polaris

Shopify Polaris ist das offizielle Design-System und gibt Ihrer App den nativen Shopify-Look:

App Dashboard mit Polaris Componentstypescript
// app/Dashboard.tsx
import {
Page,
Card,
Button,
Banner,
DataTable,
Badge
} from '@shopify/polaris';
import { useState, useEffect } from 'react';

export default function Dashboard() {
const [syncing, setSyncing] = useState(false);
const [stats, setStats] = useState(null);

useEffect(() => {
  fetchStats();
}, []);

const syncData = async () => {
  setSyncing(true);
  try {
    await fetch('/api/sync', { method: 'POST' });
    await fetchStats();
  } catch (error) {
    console.error('Sync failed:', error);
  } finally {
    setSyncing(false);
  }
};

const fetchStats = async () => {
  const response = await fetch('/api/stats');
  const data = await response.json();
  setStats(data);
};

return (
  <Page
    title="App Dashboard"
    subtitle="Verwalten Sie Ihre Synchronisierungen"
  >
    {stats?.lastSync && (
      <Banner status="success" title="Letzte Synchronisierung">
        {new Date(stats.lastSync).toLocaleString('de-DE')}
      </Banner>
    )}

    <Card sectioned>
      <div style={{ marginBottom: '1rem' }}>
        <Button
          primary
          loading={syncing}
          onClick={syncData}
        >
          Daten synchronisieren
        </Button>
      </div>

      {stats && (
        <DataTable
          columnContentTypes={['text', 'numeric', 'text']}
          headings={['Entität', 'Anzahl', 'Status']}
          rows={[
            ['Produkte', stats.products, <Badge status="success">Aktuell</Badge>],
            ['Bestellungen', stats.orders, <Badge status="success">Aktuell</Badge>],
            ['Kunden', stats.customers, <Badge status="info">Synchronisiert</Badge>]
          ]}
        />
      )}
    </Card>
  </Page>
);
}

Moderne Alternative: Shopify App Bridge 3.0

Für Embedded Apps (die im Shopify Admin laufen) ist App Bridge essentiell:

App Bridge 3.0 Setuptypescript
// app/app-bridge-setup.ts
import { createApp } from '@shopify/app-bridge';
import { Redirect, Toast } from '@shopify/app-bridge/actions';

// App Bridge initialisieren
const app = createApp({
apiKey: process.env.SHOPIFY_API_KEY!,
host: new URLSearchParams(window.location.search).get('host')!,
});

// Navigation innerhalb Shopify Admin
export const redirectToProduct = (productId: string) => {
const redirect = Redirect.create(app);
redirect.dispatch(Redirect.Action.ADMIN_PATH, {
  path: `/products/${productId}`,
});
};

// Toast-Benachrichtigungen
export const showToast = (message: string, isError = false) => {
const toast = Toast.create(app, {
  message,
  duration: 3000,
  isError,
});
toast.dispatch(Toast.Action.SHOW);
};

3. Datenbank

Empfehlung: PostgreSQL oder MongoDB

  • PostgreSQL: Wenn Sie strukturierte Daten haben (Orders, Customers, Products)
  • MongoDB: Wenn Sie flexible Schemas brauchen (JSON-artige Datenstrukturen)
  • Redis: Für Caching und Queue-Management (zusätzlich!)

Beispiel-Schema für Multi-Shop-App:

PostgreSQL Schema für Multi-Tenant Appsql
-- shops.sql
CREATE TABLE shops (
id SERIAL PRIMARY KEY,
shop_domain VARCHAR(255) UNIQUE NOT NULL,
access_token TEXT NOT NULL, -- Verschlüsselt speichern!
scopes TEXT NOT NULL,
installed_at TIMESTAMP DEFAULT NOW(),
uninstalled_at TIMESTAMP,
plan VARCHAR(50) DEFAULT 'free',
settings JSONB DEFAULT '{}'::jsonb,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_shops_domain ON shops(shop_domain);
CREATE INDEX idx_shops_installed ON shops(installed_at) WHERE uninstalled_at IS NULL;

-- webhooks.sql
CREATE TABLE webhooks (
id SERIAL PRIMARY KEY,
shop_id INTEGER REFERENCES shops(id) ON DELETE CASCADE,
topic VARCHAR(100) NOT NULL,
webhook_id BIGINT NOT NULL, -- Shopify Webhook ID
address TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_webhooks_shop ON webhooks(shop_id);

-- sync_logs.sql
CREATE TABLE sync_logs (
id SERIAL PRIMARY KEY,
shop_id INTEGER REFERENCES shops(id) ON DELETE CASCADE,
entity_type VARCHAR(50) NOT NULL, -- 'products', 'orders', etc.
sync_started_at TIMESTAMP NOT NULL,
sync_finished_at TIMESTAMP,
records_processed INTEGER DEFAULT 0,
errors_count INTEGER DEFAULT 0,
status VARCHAR(20) DEFAULT 'pending', -- pending, running, completed, failed
error_message TEXT,
metadata JSONB DEFAULT '{}'::jsonb
);

CREATE INDEX idx_sync_logs_shop_status ON sync_logs(shop_id, status);

4. Hosting

Für Private Apps:

  • Vercel/Netlify: Perfekt für kleinere Apps mit Serverless Functions
  • Railway/Render: Gut für Apps mit Datenbank
  • AWS/GCP: Für enterprise-grade Apps mit hoher Last

Für Public Apps:

  • AWS/GCP/Azure: Skalierbarkeit ist Pflicht
  • Kubernetes: Wenn Sie viele Händler erwarten (100+)
  • Managed Database: RDS (AWS), Cloud SQL (GCP), or managed PostgreSQL

Die wichtigsten Shopify APIs

Admin API (REST & GraphQL)

Zugriff auf Shop-Daten:

  • Produkte erstellen/bearbeiten
  • Orders verwalten
  • Kunden-Daten abrufen
  • Inventar synchronisieren

Best Practice: GraphQL verwenden!

GraphQL ist effizienter als REST für komplexe Abfragen:

GraphQL: Produkte mit Varianten abrufengraphql
# query-products.graphql
# Vorteil: Eine Query für alle Daten (statt mehrere REST-Calls)
query GetProductsWithVariants($first: Int!) {
products(first: $first, sortKey: UPDATED_AT, reverse: true) {
  edges {
    node {
      id
      title
      handle
      status
      totalInventory
      createdAt
      updatedAt

      # Vendor & Product Type
      vendor
      productType

      # Variants mit Pricing
      variants(first: 100) {
        edges {
          node {
            id
            title
            sku
            price
            compareAtPrice
            inventoryQuantity
            inventoryPolicy
            availableForSale

            # Metafields (Custom Data)
            metafields(first: 10) {
              edges {
                node {
                  key
                  value
                  namespace
                }
              }
            }
          }
        }
      }

      # Images
      images(first: 10) {
        edges {
          node {
            id
            url
            altText
            width
            height
          }
        }
      }

      # SEO
      seo {
        title
        description
      }
    }
    cursor
  }
  pageInfo {
    hasNextPage
    endCursor
  }
}
}

Wichtige Rate Limits verstehen:

Rate Limit Handling mit Exponential Backofftypescript
// utils/shopify-api.ts
import { GraphQLClient } from 'graphql-request';

export class ShopifyGraphQL {
private client: GraphQLClient;
private currentCost = 0;
private maxCost = 1000; // GraphQL Cost Limit pro Sekunde

constructor(shop: string, accessToken: string) {
  this.client = new GraphQLClient(
    `https://${shop}/admin/api/2025-01/graphql.json`,
    {
      headers: {
        'X-Shopify-Access-Token': accessToken,
        'Content-Type': 'application/json',
      },
    }
  );
}

async query<T>(query: string, variables?: any): Promise<T> {
  return this.retryWithBackoff(async () => {
    const response = await this.client.request(query, variables);

    // GraphQL Cost aus Extensions auslesen
    const extensions = (response as any).extensions;
    if (extensions?.cost) {
      this.currentCost = extensions.cost.actualQueryCost;

      // Warning bei hohen Costs
      if (this.currentCost > 800) {
        console.warn(`High query cost: ${this.currentCost}/${this.maxCost}`);
      }
    }

    return response;
  });
}

private async retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries = 3
): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error: any) {
      // Rate Limit Error (429)
      if (error.response?.status === 429) {
        const retryAfter = error.response.headers.get('Retry-After') || 2;
        const delay = Math.min(Math.pow(2, i) * 1000, 30000); // Max 30s

        console.warn(`Rate limited. Retry after ${retryAfter}s (attempt ${i + 1}/${maxRetries})`);
        await this.sleep(delay);
        continue;
      }

      // Andere Fehler: nicht retries
      if (i === maxRetries - 1) throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

private sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}
}

Storefront API

Für Headless Commerce:

  • Produkte im Frontend anzeigen
  • Cart-Funktionalität
  • Checkout-Flow

Wichtig: Storefront API ist read-only und public-facing!

Webhooks: Event-basierte Architektur

Webhooks sind essentiell für Echtzeit-Updates ohne Polling:

Webhook Registration & Managementtypescript
// services/webhook-manager.ts
import { Shopify } from '@shopify/shopify-api';

export class WebhookManager {
private shopify: Shopify;

constructor(shop: string, accessToken: string) {
  this.shopify = new Shopify({
    shopName: shop,
    accessToken,
    apiVersion: '2025-01',
  });
}

async registerAllWebhooks() {
  const webhooks = [
    { topic: 'ORDERS_CREATE', path: '/webhooks/orders/create' },
    { topic: 'ORDERS_UPDATED', path: '/webhooks/orders/update' },
    { topic: 'PRODUCTS_CREATE', path: '/webhooks/products/create' },
    { topic: 'PRODUCTS_UPDATE', path: '/webhooks/products/update' },
    { topic: 'APP_UNINSTALLED', path: '/webhooks/app/uninstalled' }, // Wichtig!
  ];

  for (const webhook of webhooks) {
    try {
      await this.registerWebhook(webhook.topic, webhook.path);
      console.log(`Registered webhook: ${webhook.topic}`);
    } catch (error) {
      console.error(`Failed to register ${webhook.topic}:`, error);
    }
  }
}

private async registerWebhook(topic: string, path: string) {
  const response = await this.shopify.graphql(`
    mutation webhookSubscriptionCreate($topic: WebhookSubscriptionTopic!, $webhookSubscription: WebhookSubscriptionInput!) {
      webhookSubscriptionCreate(topic: $topic, webhookSubscription: $webhookSubscription) {
        webhookSubscription {
          id
          topic
          endpoint {
            __typename
            ... on WebhookHttpEndpoint {
              callbackUrl
            }
          }
        }
        userErrors {
          field
          message
        }
      }
    }
  `, {
    topic,
    webhookSubscription: {
      callbackUrl: `${process.env.APP_URL}${path}`,
      format: 'JSON',
    },
  });

  if (response.data.webhookSubscriptionCreate.userErrors.length > 0) {
    throw new Error(response.data.webhookSubscriptionCreate.userErrors[0].message);
  }

  return response.data.webhookSubscriptionCreate.webhookSubscription;
}

// KRITISCH: App Uninstall Handler
async handleAppUninstall(shop: string) {
  console.log(`App uninstalled from shop: ${shop}`);

  // 1. Webhooks löschen (automatisch durch Shopify)
  // 2. Scheduled Jobs stoppen
  await this.cancelScheduledJobs(shop);

  // 3. Datenbank cleanup
  await this.markShopAsUninstalled(shop);

  // 4. Optional: Daten löschen nach GDPR-Periode (30 Tage)
  // await this.scheduleDataDeletion(shop, 30);
}

private async cancelScheduledJobs(shop: string) {
  // Implementierung abhängig von Job-Queue (BullMQ, Agenda, etc.)
}

private async markShopAsUninstalled(shop: string) {
  // Datenbank-Update
}
}

Wichtige Webhooks:

  • orders/create – Neue Bestellungen
  • orders/updated – Bestellstatus-Änderungen
  • products/update – Produktänderungen
  • customers/create – Neue Kunden
  • app/uninstalledKRITISCH! App wurde deinstalliert (Cleanup!)

Best Practices für 2025

1. Background Processing (Queues)

NIEMALS Webhook-Verarbeitung synchron machen! Shopify erwartet Response < 5 Sekunden.

BullMQ Queue Setup für Background Jobstypescript
// queues/order-queue.ts
import { Queue, Worker } from 'bullmq';
import Redis from 'ioredis';

const connection = new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
maxRetriesPerRequest: null,
});

// Queue für Order-Processing
export const orderQueue = new Queue('orders', { connection });

// Worker für Order-Processing
const orderWorker = new Worker('orders', async (job) => {
const { shop, order } = job.data;

console.log(`Processing order ${order.id} for shop ${shop}`);

try {
  // Beispiel: Order zu externem System senden
  await sendOrderToERP(shop, order);

  // Success
  return { success: true, orderId: order.id };
} catch (error) {
  console.error('Order processing failed:', error);
  throw error; // Retry automatisch
}
}, {
connection,
concurrency: 5, // 5 Jobs parallel
limiter: {
  max: 10, // Max 10 Jobs
  duration: 1000, // pro Sekunde
}
});

// Job Events
orderWorker.on('completed', (job) => {
console.log(`Job ${job.id} completed`);
});

orderWorker.on('failed', (job, error) => {
console.error(`Job ${job.id} failed:`, error);
});

// Graceful Shutdown
process.on('SIGTERM', async () => {
await orderWorker.close();
await orderQueue.close();
await connection.quit();
});

2. Monitoring & Error Tracking

Essential Tools:

  • Sentry für Error Tracking
  • Datadog/New Relic für Performance Monitoring
  • Logtail für strukturierte Logs
Sentry Integration mit Contexttypescript
// utils/sentry.ts
import * as Sentry from '@sentry/node';

Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1, // 10% APM sampling
});

// Custom Error mit Shop-Context
export function captureShopifyError(
error: Error,
shop: string,
context?: Record<string, any>
) {
Sentry.withScope((scope) => {
  scope.setTag('shop', shop);
  scope.setContext('shopify', {
    shop,
    ...context,
  });
  Sentry.captureException(error);
});
}

3. Testing-Strategie

Integration Tests für Shopify APItypescript
// tests/shopify-api.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { ShopifyGraphQL } from '../utils/shopify-api';

describe('Shopify API Integration', () => {
let api: ShopifyGraphQL;

beforeEach(() => {
  api = new ShopifyGraphQL(
    process.env.TEST_SHOP!,
    process.env.TEST_ACCESS_TOKEN!
  );
});

it('should fetch products with pagination', async () => {
  const query = `
    query {
      products(first: 10) {
        edges {
          node {
            id
            title
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
  `;

  const result = await api.query(query);
  expect(result.data.products.edges).toBeDefined();
  expect(result.data.products.edges.length).toBeLessThanOrEqual(10);
});

it('should handle rate limits gracefully', async () => {
  // Simulate rate limit by making many requests
  const promises = Array.from({ length: 50 }, () =>
    api.query('{ shop { name } }')
  );

  await expect(Promise.all(promises)).resolves.toBeDefined();
});
});

Realistische Kosten einer Shopify App

Private App (für einen Shop)

| Kostenpunkt | Preis | Details | |-------------|-------|---------| | Entwicklung | €3.000 - €15.000 | | | Basis-App mit API-Integration | €3.000 - €5.000 | 1-2 Wochen | | Custom UI (Admin-Bereich) | +€1.500 - €3.000 | React + Polaris | | Komplexe Business-Logik | +€3.000 - €7.000 | ERP-Integration, etc. | | Hosting (monatlich) | €20 - €150 | | | Vercel/Netlify (Serverless) | €20 - €50 | Kleine Apps | | Railway/Render (mit DB) | €50 - €100 | Mittlere Apps | | AWS/GCP (skalierbar) | €100 - €150 | Enterprise | | Wartung (jährlich) | €600 - €3.000 | | | Updates & Bug Fixes | €600 - €1.200 | 1-2 Tage/Quartal | | Feature-Erweiterungen | €1.200 - €2.400 | Variable |

Gesamtkosten (Jahr 1): €4.000 - €20.000

Public App (für App Store)

| Kostenpunkt | Preis | Details | |-------------|-------|---------| | MVP-Entwicklung | €18.000 - €60.000 | 3-6 Monate | | Core-Funktionalität | €10.000 - €30.000 | Multi-Tenant | | UI/UX Design | €3.000 - €8.000 | Professionell | | Testing & QA | €2.000 - €7.000 | Umfassend | | App Store Submission | €1.000 - €3.000 | Review-Prozess | | Hosting (skalierbar) | €150 - €1.000/Monat | AWS/GCP | | Support & Wartung | €6.000 - €30.000/Jahr | | | Marketing | €3.000 - €30.000/Jahr | SEO, Ads |

Gesamtkosten (Jahr 1): €30.000 - €120.000+

7 kritische Fehler (und wie Sie sie vermeiden)

1. API Rate Limits ignorieren

Shopify limitiert API-Calls: 40 Requests/Sekunde (REST), 1.000 Punkte/Sekunde (GraphQL).

Lösung: Implementieren Sie Queues und exponential backoff (siehe Code-Beispiele oben)

2. Webhooks nicht verifizieren

Jeder Webhook MUSS verifiziert werden (HMAC-Signature), sonst sind Sie anfällig für gefälschte Requests.

3. Keine Fehler-Behandlung für App-Uninstalls

Wenn ein Händler Ihre App deinstalliert, müssen Sie:

  • Webhooks löschen
  • Datenbank-Einträge cleanen
  • Scheduled Jobs stoppen
  • Optional: GDPR-konforme Datenlöschung einplanen

Immer app/uninstalled Webhook implementieren!

4. Synchrone Webhook-Verarbeitung

Problem: Webhook-Handler verarbeitet Order synchron → Timeout nach 5s → Shopify deaktiviert Webhook

Lösung: Webhook sofort mit 200 OK beantworten, Processing in Queue verschieben

5. OAuth-Flow falsch implementiert

Shopify nutzt OAuth 2.0. Ein falscher Flow führt zu Security-Problemen.

Verwenden Sie die offizielle Library:

npm install @shopify/shopify-api

6. Keine strukturierten Logs

Ohne Logging sind Fehler nicht nachvollziehbar.

Empfehlung:

  • Structured Logging: JSON-Format mit Context
  • Log Levels: ERROR, WARN, INFO, DEBUG
  • Log Aggregation: Datadog, Logtail, CloudWatch

7. Keine Monitoring-Alerts

Setzen Sie Alerts für:

  • Error Rate > 5%
  • Response Time > 2s
  • Queue-Backlog > 1000 Jobs
  • Database Connection Errors
  • Shopify API Errors (401, 429, 500)

Deployment & CI/CD

GitHub Actions Pipeline für Shopify Appyaml
# .github/workflows/deploy.yml
name: Deploy Shopify App

on:
push:
  branches: [main]
pull_request:
  branches: [main]

jobs:
test:
  runs-on: ubuntu-latest

  services:
    postgres:
      image: postgres:15
      env:
        POSTGRES_PASSWORD: postgres
      options: >-
        --health-cmd pg_isready
        --health-interval 10s
        --health-timeout 5s
        --health-retries 5

  steps:
    - uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run linter
      run: npm run lint

    - name: Run tests
      run: npm test
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test

    - name: Build
      run: npm run build

deploy:
  needs: test
  runs-on: ubuntu-latest
  if: github.ref == 'refs/heads/main'

  steps:
    - uses: actions/checkout@v4

    - name: Deploy to Railway
      uses: bervProject/railway-deploy@main
      with:
        railway_token: ${{ secrets.RAILWAY_TOKEN }}
        service: shopify-app

    - name: Run migrations
      run: npm run migrate:prod
      env:
        DATABASE_URL: ${{ secrets.DATABASE_URL }}

    - name: Notify deployment
      uses: 8398a7/action-slack@v3
      with:
        status: ${{ job.status }}
        text: 'Deployment completed'
        webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Wann sollten Sie KEINE Custom App bauen?

Nicht jedes Problem braucht eine App. Prüfen Sie zuerst:

Es gibt bereits eine App im Store → Nutzen Sie die (günstiger!) ❌ Sie brauchen nur einfache Automatisierung → Shopify Flow reicht oft ❌ Einmalige Daten-Migration → Script über Admin API ❌ Budget < €3.000 → Keine nachhaltige Custom-Entwicklung möglich ❌ Keine technische Expertise im Team → Wartung wird problematisch

Fazit: Ist eine Custom App das Richtige für Sie?

Eine Custom Shopify App lohnt sich, wenn:

  • ✅ Standard-Apps Ihre Business-Logik nicht abdecken
  • ✅ Sie externe Systeme (ERP, CRM, PIM) anbinden müssen
  • ✅ Sie individuelle Workflows automatisieren wollen
  • ✅ Sie Budget für professionelle Entwicklung haben (min. €3.000)
  • ✅ Sie technische Ressourcen für Wartung haben

Eine Public App lohnt sich, wenn:

  • ✅ Sie eine skalierbare SaaS-Lösung bauen wollen
  • ✅ Ihr Problem viele Shopify-Händler betrifft
  • ✅ Sie langfristig in Entwicklung, Support und Marketing investieren können
  • ✅ Sie ein Team haben (min. 2-3 Entwickler)

Nächste Schritte: Ihre Custom App professionell umsetzen

Sie haben ein konkretes Projekt im Kopf? In einem kostenlosen Erstgespräch analysiere ich:

  • Welche API-Endpoints Sie brauchen
  • Ob eine Private oder Public App die richtige Wahl ist
  • Realistische Kosten und Zeitplanung
  • Technische Risiken und wie Sie diese minimieren
  • Tech-Stack-Empfehlungen für Ihr Projekt

Brauchen Sie eine Custom Shopify App?

Lassen Sie uns Ihre Anforderungen besprechen und einen klaren technischen Lösungsweg entwickeln.

Kostenloses Erstgespräch


Über den Autor: Justin Kreutzmann ist Shopify-Entwickler mit Fokus auf Custom Apps, Headless Commerce und ERP-Integrationen. Er hat 50+ E-Commerce-Projekte umgesetzt und berät Unternehmen bei komplexen Shopify-Architekturen.