DEV Community

Cover image for Magento Go Migration: Shared DB, CDC, or Event Bus?
Tuấn Anh
Tuấn Anh

Posted on • Originally published at tanhdev.com

Magento Go Migration: Shared DB, CDC, or Event Bus?

You rewrote your Magento auth endpoint in Go. It drops from 180ms to 8ms. You're thrilled.

Then you realize Go is still reading from customer_entity — with 5–10 JOINs across EAV tables. The bottleneck was never PHP. It was the schema.

So now what?

There are three paths forward when migrating Magento to a Go backend. Picking the wrong one early is expensive to undo.


Option A — Shared Database

Go connects directly to Magento's existing MySQL.

PHP Magento ──WRITE──▶ MySQL Magento (shared) ◀──READ── Go Service
                                               ◀──WRITE─ Go Service
Enter fullscreen mode Exit fullscreen mode

What you get:

  • ✅ Instant latency win (22× faster — PHP bootstrap overhead gone)
  • ✅ Zero data sync lag — both systems read the same committed rows
  • ✅ Trivial rollback — one config change flips traffic back to PHP

What breaks you later:

  • ❌ Schema coupling — every Magento 2.4.x upgrade is a runtime risk for your Go structs
  • ❌ EAV performance unchanged — Go executes the same 10-JOIN query, just faster
  • ❌ Race conditions — writing to oauth_token and customer_entity from both PHP and Go creates corrupted auth state, not a DB error
  • ❌ Distributed monolith trap — one failure domain, two codebases, harder to debug

Adobe deprecated the "split database" feature in Magento 2.4.6+. Every upgrade consolidates the schema further. Each Go struct pointing at a Magento table is an undeclared dependency with no SLA.

Use when: you need results in weeks. But set a hard Phase 2 deadline — this state becomes permanent by inertia.


Option B — CDC + Debezium ✅ Recommended

Debezium reads MySQL's binlog directly. Zero PHP code changes required.

PHP Magento ──WRITE──▶ MySQL Magento
                            │ binlog (no PHP changes needed)
                            ▼
                       Debezium CDC Engine
                            │ stream events
                            ▼
Go Service ──WRITE──▶ Go DB (flat schema, Go-owned)
Enter fullscreen mode Exit fullscreen mode
# debezium-connector.yaml
connector.class: io.debezium.connector.mysql.MySqlConnector
database.hostname: magento-mysql-master
table.include.list: magento.customer_entity, magento.catalog_product_entity
# reads binlog — zero PHP changes required
Enter fullscreen mode Exit fullscreen mode

Go writes use the Outbox Pattern — atomically within the same DB transaction:

// Single transaction — no dual-write risk
tx.Exec(`INSERT INTO go_customer_token (...) VALUES (...)`)
tx.Exec(`INSERT INTO go_outbox (event_type, payload) VALUES ('TOKEN_CREATED', $1)`, payload)
// OutboxProcessor publishes to Kafka every 500ms
Enter fullscreen mode Exit fullscreen mode

What you get:

  • ✅ Go owns its schema — flatten EAV → 5× read speed
  • ✅ ACID writes on Go's own DB
  • ✅ No PHP Magento code changes
  • ✅ Per-domain rollout (Auth first, Checkout always last)
  • ✅ CDC lag 50–200ms — acceptable for most use cases

Option C — Full Event Bus (Kafka)

Both systems fully isolated. All comms go through Kafka topics only.

         EVENT BUS (Kafka)
         ┌──────────────────────────────────┐
         │ customer.updated │ order.created │
         └────────┬─────────────────┬───────┘
                  │ PUBLISH         │ CONSUME
                  ▼                 ▼
           PHP Magento         Go Service
           MySQL (owned)       Go DB (owned)
Enter fullscreen mode Exit fullscreen mode

The catch: Magento must publish every state change as a domain event. Customer updated, order status changed, inventory adjusted — all of it. If the PHP team misses a single event category, Go's DB silently diverges. Forever.

⚠️ Common mistake: Publishing directly to Kafka after the DB commit (not inside the transaction) creates a dual-write gap. If Kafka publish fails, the event is lost silently and Go's DB diverges permanently. Always use the Outbox Pattern — write to an outbox table inside the DB transaction first.

Use when: the PHP team can commit to building and maintaining the event publisher for every Magento domain. Timeline: 12–18 months.


The Decision Framework

Q1: 2+ engineers with distributed systems experience?
  └─ NO  → Option A + guardrails (schema pinning, read-only policy)
  └─ YES → Q2

Q2: Inventory oversell tolerance = zero?
  └─ YES → Option B (ACID writes, no eventual consistency at write time)
  └─ NO  → B or C both viable

Q3: Need Go to scale independently of Magento's DB?
  └─ NO  → Option B is sufficient
  └─ YES → Q4

Q4: PHP team can build + maintain event publishers?
  └─ NO  → Option B required (CDC = no PHP changes)
  └─ YES → Option C viable (12–18 months)
Enter fullscreen mode Exit fullscreen mode

Domain Migration Order (regardless of option)

Domain Priority Risk
Auth / OIDC First Low — Go already owns token logic
Wishlist Second Low — small data footprint
Customer read Second Medium — flatten EAV
Customer write Third Medium — needs Saga
Cart / Checkout Last High — never migrate until Saga is proven

Full Breakdown

The full post includes a 16-dimension comparison matrix, risk table per option, infrastructure checklist (Debezium prerequisites), and a 24-month recommended roadmap.

👉 Read the full guide on tanhdev.com


Have you gone down the Event Bus route with Magento? Curious how the PHP event publisher held up in production — drop a comment below.

Top comments (0)