From Canvas to Code: Planning a Migration Path That Will Not Break
How to plan a migration off Canvas (Airdev) to a modern code stack without losing what works. The signals, the sequencing, and the patterns specific to Canvas apps.
Migrating off Canvas (Airdev's Bubble framework) is more nuanced than migrating off vanilla Bubble. Canvas apps are usually older, larger, and more architecturally opinionated than non-Canvas Bubble apps. That has implications for how the migration runs and what is worth carrying forward.
This article describes the migration path we use at AppSavvy when Canvas apps are ready to leave the platform. It is specifically about Canvas migrations - if you are on vanilla Bubble, the Bubble to Next.js migration guide is the right starting point.
Signals that say it is time
Canvas apps usually do not migrate because of a single trigger. They migrate because three or four signals stack up over time. The most common ones we see:
- The app is on Canvas v5 and the cost of rebuilding on v6 is approaching the cost of a code migration
- Performance issues that cannot be solved with Canvas's available tools
- Plugin sprawl (more than one plugin in the "abandoned but critical" bucket)
- AI features being added via a code service alongside Canvas, with the code service growing
- Senior engineering hires repeatedly preferring not to take the role
- Customer requirements (compliance, data residency, performance SLAs) that Bubble cannot meet
If you have three or more of these, migration becomes a serious conversation. The longer you wait past three signals, the more expensive the migration becomes.
What is different about Canvas migrations
A Canvas migration is not just a Bubble migration with more code. A few patterns are specifically Canvas-shaped:
Canvas apps tend to have heavy reusable element trees
Canvas encourages component reuse. Mature Canvas apps usually have a deep tree of reusables that compose with each other. Migrating this naively (one reusable at a time, in tree order) often results in a code app whose component structure mirrors the Canvas one - even where a flatter or differently-organised structure would be better.
The discovery phase needs to take a hard look at the reusable tree and decide which abstractions to carry forward.
Canvas style systems do not transfer directly
Your Canvas style variables do not map 1:1 to CSS variables or to a design system in a code stack. The semantic intent transfers; the literal variable names usually need to be revisited.
This is an opportunity. Most Canvas apps have accumulated some style debt over the years; the migration is a chance to clean it up.
Canvas conventions can hide important logic
Canvas's built-in conventions (the way it handles modals, the standard auth flow, the search patterns) are usually fine in isolation. Reproducing them naively in code can result in a codebase that has the same shape as the Canvas app instead of an idiomatic React/Next.js app.
The good migrations explicitly decide what to inherit from Canvas conventions and what to redesign.
Plugin replacement is more involved
Canvas apps tend to use more plugins than non-Canvas Bubble apps. Each plugin needs a replacement strategy: native code, an off-the-shelf library, a small custom build, or a third-party service.
This is part of the discovery and architecture phases, but it specifically shapes the migration scope.
The six phases, applied to Canvas
The general migration playbook has six phases. Here is how each one specifically applies to Canvas migrations.
Phase 1: Discovery (2-3 weeks)
Same as a non-Canvas Bubble discovery, plus:
- Audit the Canvas version and any version-specific patterns the app depends on
- Map the reusable element tree explicitly
- Document any custom Canvas extensions or patterns the team has built
- Catalogue plugin dependencies with replacement strategies
The discovery for a Canvas app usually takes one week longer than a vanilla Bubble app of the same size because of the additional structure to map.
Phase 2: Architecture (2-3 weeks)
The target architecture is typically:
- Next.js on Vercel (replaces Bubble + Canvas as the application platform)
- Supabase Postgres (replaces Bubble's database)
- Drizzle ORM in TypeScript (gives you schema as code)
- Trigger.dev (replaces API workflows and scheduled workflows)
- A component library that replaces Canvas's reusable elements (often shadcn/ui or a custom library)
- Tailwind CSS for styles (replaces the Canvas style system, mapped from the existing semantic variables)
The Canvas-specific architecture work is mostly about the component library: deciding what to build vs. adopt and how to handle the conventions that Canvas inherits from Airdev's framework.
Phase 3: Foundation (1 week)
Same as any migration. Provision Supabase, Vercel, Trigger.dev, GitHub Actions. Set up the component library skeleton. Establish the typography and colour tokens.
Phase 4: Vertical slice migration (10-16 weeks)
Slightly longer than a non-Canvas migration of the same size, because Canvas's component reuse means each slice often touches multiple shared components.
The order we usually use:
- Auth (the foundation everything else depends on)
- The core "noun" of the app (orders, bookings, projects, whatever)
- One end-to-end user flow that exercises a representative slice of features
- The rest of the user flows
- Admin features
- Reporting and analytics
The first three weeks of slice migration are often slower than the average; once the component library is mature, slices ship faster.
Phase 5: Data migration (1-2 weeks)
Same approach as a non-Canvas Bubble data migration. Idempotent, chunked, resumable imports from Bubble's data API to Postgres.
The Canvas-specific note is that Canvas apps often have option sets that are larger than vanilla Bubble apps (because the framework encourages structured data). The migration of option sets to lookup tables or enums needs care.
Phase 6: Cutover and partnership (1 week + ongoing)
Same as any migration. DNS switches. Bubble app becomes read-only. Ongoing support for the first month or longer.
Total timeline
A typical Canvas-to-code migration for a mid-stage app runs 16-24 weeks end-to-end. Larger or more integration-heavy apps can run 6-9 months.
This is longer than a vanilla Bubble migration of equivalent business complexity, because Canvas apps are usually structurally larger.
What to keep, what to redesign
A short rule of thumb for the architecture phase:
Keep:
- The data model (with adjustments for normalisation and consistency)
- The user-facing flows (the product is the product)
- The core integrations (Stripe, your supplier APIs, etc.)
- The visual design (Canvas apps usually have decent design discipline)
Redesign:
- The component structure (Canvas reusables do not map cleanly to React components)
- The async work patterns (Trigger.dev gives you better semantics than recursive workflows)
- The auth and permissions model (Postgres RLS is more rigorous than Bubble privacy rules - and you will find existing rules that did not actually protect what you thought)
- The plugin replacements (this is largely "what to replace plugins with")
Drop:
- Custom code escape hatches (re-implement properly in the new app)
- Features that were not actively used
- Plugins that were workarounds for things native code handles cleanly
Cost ranges
For planning purposes:
| App size | Approximate cost | Approximate timeline |
|---|---|---|
| Small Canvas app (20 reusables, 30 workflows) | $80k-150k | 12-16 weeks |
| Medium Canvas app (50 reusables, 80 workflows) | $150k-250k | 16-22 weeks |
| Large Canvas app (100+ reusables, 200+ workflows) | $250k-450k+ | 22-36 weeks |
These ranges assume our typical engagement model: fixed-scope, fixed-price, no T&M overruns. They are not quotes for a specific app - actual numbers depend on the discovery phase.
When to stay on Canvas instead
Some Canvas apps should not migrate. The two cases we see most often:
- The app is in steady state. It works, it earns, the team is small, the roadmap is light. Stay on Canvas with a maintenance retainer.
- You are pre-PMF. If you are still iterating on what the product is, the speed advantage of Canvas usually outweighs the long-term cost. Migrate when you know what you are building.
We have advised both. We would rather lose a migration engagement than ship someone a migration they did not need.
What to do next
If you are evaluating a Canvas-to-code migration, the Bubble migration playbook PDF is the closest thing to a complete walkthrough of how we run the work. The phases apply to Canvas with the additions described above.
If you would like a senior ex-Airdev engineer to look at your specific Canvas app and tell you honestly whether migration is the right move, book a 30-minute discovery call. We will not try to sell you a migration if the math does not say to migrate.
If you want an external audit first, request a free Bubble app audit.
Read next: Canvas v5 to v6: upgrade, rebuild, or migrate and Bubble to Next.js migration guide.
Got a Bubble or Canvas app you’d like a second pair of eyes on?
30-minute discovery call. We’ll look at your app live and tell you honestly what we’d do next.
Or grab the Bubble migration playbook PDF.