Canva had to migrate millions of media asset metadata records from MySQL to DynamoDB without dual writes or reading the binlog. What they did was super lazy and interesting…
Instead of deciding upfront which records to migrate and when, they let production traffic decide.
Every time a media asset was created, updated, or even just read, a message containing only the asset ID was dropped into an SQS queue. A worker then picked it up, fetched the latest state from MySQL, and synced it to DynamoDB. Thus, no dual writes and no binlog parsing.
During this phase, MySQL remained the source of truth, and DynamoDB was just a derived copy.
What’s interesting here is that the hottest data gets migrated first. Cold historical data gets queued in the background at a lower priority via a full backfill scan. This means MySQL starts shedding real load almost immediately, not at the end of the migration.
Now that the data resides in two places, they performed sequential reads (Dynamo-first) in production, with fallback to MySQL. In shadow, they compared results against MySQL to ensure consistency and catch bugs in the migration logic.
Once the data was fully migrated and validated, they switched writes to DynamoDB. After this cutover, DynamoDB became the source of truth, and MySQL was eventually retired.
The lazy replicated write approach is interesting and efficient when it comes to migrating a read-heavy system from one database to another.
Hope this helps.
btw, enrollments open for sys design April cohort (sessions start from 28th March, ~11 seats left) - arpitbhayani.me/course