Why Internal Tools Break at 50 Employees (and How to Fix Them)
Learn why internal tools fail as teams grow past 50 people, and the architecture and process fixes that prevent recurring breakdowns.
A guide for teams leaving Bubble, built around Claude Code and Codex. This is for founders and CEOs who built a business on Bubble and are starting to feel the platform’s shortcomings.
Migration is a business decision before it’s a technical one. A real Bubble app, with paying customers and workflows, takes a few months to rebuild properly. Teams that have done this quote three to five months per app, and they are not padding the estimate.
Budget-wise, most teams land somewhere between $15k and $25k for a full rebuild, depending on the features and data complexity. If you prefer DIY, it costs your team time rather than cash.
The benefit of migrating is that you own the code, the app gets faster, and you become fundable and acquirable in a way a Bubble app never quite is. What you take on are the things Bubble was quietly doing for you, like security patching, backups, and uptime, which are now yours.
But with Claude Code and Codex, a much smaller team can rebuild what used to take a full team six months.
Bubble is good at a lot of things. It can take your idea in front of paying users without a dev team, but there is a ceiling, and there are signs you’ve hit it.
But the mistake people make here is treating migration as all-or-nothing. It isn’t.
You have a few options before completely rebuilding your Bubble app. You can rebuild only the part that’s actually broken, and leave the rest on Bubble.
One of our clients had a well-managed Bubble app that needed a WebSocket service to manage a fleet of connected fridges. We didn’t recommend a full migration.
A custom backend component that connected the hardware to the existing app was all they needed. Everything else stayed in Bubble.
That’s the kind of call worth making before you begin migrating your Bubble app. We help teams with a migration audit before committing to a rebuild. If you’re evaluating whether an agent fits your process before deciding on a migration, start with what an AI agent actually is.
If there is one thing Bubble cannot do, you can still build that feature with code and use Bubble for everything else.
If the performance and cost are causing issues, but the app is working, plan a full rebuild in phases.
If you’ve hit the ceiling everywhere, like raising funding, or you want to own the source code, plan a full migration.
However, if you’re still finding product-market fit or the app changes weekly, stay on Bubble. Migrating now is premature.
One thing Bubble can't do, everything else is fine
Build that one piece in code, keep the rest on Bubble
Performance and cost hurt, but the app works
Plan a full rebuild, done in phases
You've hit the ceiling everywhere (funding, ownership)
Plan a full migration
Still finding product-market fit, app changes weekly
Stay on Bubble. Migrating now is premature
A common mistake is to frame the move as a way of running away from Bubble’s problems. It is correct, but incomplete.
You can create live dashboards, collaborative editing, and instant notifications. Users see updates immediately without refreshing the page, making the application feel responsive and modern.
You can integrate AI models directly into your product instead of relying on restrictive third-party plugins. This gives you full control over model choice, performance, capabilities, and cost.
Build genuine iOS and Android applications with native performance, device integrations, and a polished user experience, rather than creating a wrapped web app.
You can run long-running and compute-intensive jobs reliably in the background without being constrained by usage quotas.
You can optimise database queries, caching, and application architecture to improve user experience.
Choose your cloud provider, deployment strategy, and scaling approach while meeting your security, compliance, and cost requirements.
Keep costs predictable by paying for the infrastructure you use rather than being charged for every workflow execution or user action.
Bubble: Create a data type in the Data tab and add fields.
Code: Define a database schema, and an AI agent generates the migration.
Bubble: Use “Do a search for” with constraints.
Code: Write a query using SQL or an ORM, with the AI agent generating most of the implementation.
Bubble: Build workflows by dragging actions onto the workflow canvas.
Code: Define functions that run in response to events, with the AI agent implementing the logic.
Bubble: Add “Only when” conditions to actions.
Code: Use standard if statements and other programming constructs.
Bubble: Authentication is built in and works out of the box.
Code: Choose an authentication provider and integrate it into your application.
Bubble: Files are uploaded and stored automatically.
Code: Configure object storage and implement the upload flow yourself.
Bubble: Connect APIs using the API Connector without writing code.
Code: Make direct API calls, giving you complete control over requests, authentication, and error handling.
Bubble: Use a built-in action or a plugin.
Code: Integrate an email service and configure deliverability settings such as SPF and DKIM.
Bubble: Use “Schedule API Workflow.”
Code: Run scheduled tasks with cron jobs or background workers.
Bubble: Configure Privacy Rules.
Code: Implement row-level security and server-side authorisation.
Bubble: Click Preview or Deploy.
Code: Commit changes to Git, let CI run tests, and deploy through a release pipeline.
Bubble: Step through workflows using the debugger.
Code: Inspect logs, run automated tests, and reproduce issues locally.
Bubble: Rely on Bubble’s save points and version history.
Code: Use Git for complete version history, branching, code reviews, and reliable rollbacks.
Almost every expensive mistake in a Bubble migration comes from a required mindset change.
In Bubble, you dragged workflow steps. In code, logic lives in functions that run when something happens: a user clicks, an API is triggered, or a timer fires.
The logic is the same. The “where do I see it” is completely different, and that’s the first thing that throws people.
Bubble’s data types become tables. Fields become columns.
You now need to create rules. A field that’s supposed to hold a number will reject text. Bubble was easy. Postgres is not, and the strictness is both a feature and, during migration, an area where many mistakes happen.
In Bubble, Privacy Rules decided who could see what. In custom code, nothing is protected until you write the protection. The default state of a new app is open. Every rule you had in Bubble has to be rebuilt. If you skip it, you become prone to a data breach.
Bubble bundled the frontend, backend, database, and hosting into a single editor. With custom code, these are separate services. That sounds like more to manage, and it is, but it’s also exactly what lets two AI agents work on different parts simultaneously.
The Bubble plugin you installed with a click becomes a library or an API you call directly. This means more control and more reliability, but slightly more setup.
There is no ‘one-click app migration’ button in Bubble. You cannot export your HTML or your workflows. What you can export is your data, and even that has some challenges.
The Data tab lets you download each data type as a CSV. Because you have editor access, this bypasses Privacy Rules, so you see everything.
The Data API returns 100 records per request, which means you need cursor-based pagination to fetch everything.
Then there is the file-and-image issue. When you export a CSV, your files and images are not in it. What’s in it are the URLs pointing to where Bubble hosts those files. If you migrate without transferring your files, those URLs will go dead, and the assets will be gone.
Workflows and UI have to be created from scratch because none of your logic exports. Someone has to write down what each workflow does.
This is tedious, and a lot of your time will be spent here. But the document you are producing is your spec. It’s exactly what the AI agents will build from.
And audit your Privacy Rules now, before you lose access to them. Write down every single one as it defines your whole authorisation model. If it’s incomplete, your new app will be missing security rules you didn’t know you had.
Every time a user uploaded a profile photo or a PDF to your Bubble app, Bubble stored it in AWS and returned a URL for it. In custom code, you choose S3 or Cloudflare R2, and have to create the pipeline for it.
The migration itself has a specific order of operations, and getting it wrong will result in permanent data loss.
First, export your data, remembering that you get URLs, not files. Then run a script that downloads every file from every URL before Bubble hosting goes away. Then re-upload everything to your new storage. And lastly, rewrite every stored URL in your database to point at the new location.
Some Bubble URLs are signed and expire, so you have to decide which files are public and which are private. And Bubble was using a CDN to serve files quickly worldwide, while enforcing file size and access rules. All of that is now yours to set up.
None of it is hard in isolation. The problem is not knowing it existed until a user reports their files are gone.
Someone who has never migrated an app before will not consider this to be a major challenge.
Bubble’s database is simple. Fields can be empty when they shouldn’t be. A field can hold a number for 9,000 records and text for the other 12. Relationships between things are stored by reference and drift out of sync over years of real use. None of this caused obvious problems in Bubble, because Bubble didn’t enforce strictness.
Then you move to Supabase or Xano, and the import fails. Because your data violates the rules.
Null values where a value is required. Orphaned references pointing to records that were deleted. Duplicate emails in a field that’s supposed to be unique. Dates are stored in three different formats.
Your Option sets are exported as IDs or display text, not as foreign keys, making it difficult to link them to the proper relational data.
Bubble will export linked “things” as reference IDs, not as the readable relationships you see in the editor, and reconstructing how everything connects takes a lot of work.
The time you spend cleaning, deduplicating, and reconciling exported Bubble data will always exceed the time spent writing the import itself.
This is usually the point where teams want a second pair of eyes.
We've done these migrations before: the file rehosting, the auth cutover, the Privacy Rules audit. Talk it through before you commit to a plan.
Bubble will not let you export your users’ password hashes. It’s a good thing these are hard to extract. But it means you cannot simply move your users’ passwords to a new system and have everyone log in as if nothing changed.
The first solution is a forced password reset. Everyone moves at once. On cutover, every user has to reset their password, and you email them a reset link. The upside is a clean, simple, all-at-once switch. For the companies we helped migrate, we pick a low-traffic window like a weekend.
The second is trickle migration. You keep the new auth system alongside the old one. The first time each user logs in after cutover, the new system checks their credentials against the old Bubble system once, then stores the password. From then on, they are fully migrated.
For most apps with fewer than a few thousand users, a forced reset is simpler and worth the small friction. Use the trickle approach when a forced reset would cost you users or when downtime is expensive.
Beyond passwords, you still need to migrate everything else about your users. Profiles, roles, permissions, all of it moves as data.
A few more things to plan for: all active sessions are invalidated at cutover, so everyone gets logged out once; social logins like Google have to be re-linked; and any multi-factor setup has to be re-enrolled.
You can choose between a managed auth provider like Auth0 or Clerk that handles the hard parts for a fee or an auth library you run yourself with more control and responsibility.
I always recommend paying for a managed provider unless you have a specific reason not to. Auth is one of those areas where the cost of getting it slightly wrong is very high.
In Bubble, security mostly happened whether you thought about it or not. In code, your app’s default state is unprotected, and every layer of security is something you deliberately add.
Every Bubble Privacy Rule has to be rebuilt as real server-side logic, often with row-level security in the database.
Secrets management is the next step. Secrets like API keys should be in server-side environment variables.
When the framework you built on releases a security update, it is up to you to apply it. Bubble did this for you in the background. On top of that, you now own encryption in transit and at rest, mostly handled by good defaults and your hosting choices, but now it’s your responsibility to confirm rather than assume, and input validation, because your own API endpoints are exposed to the world and have to defend themselves against bad input.
Data security is one reason why doing it alone, without anyone who has done it before, can go wrong quietly and expensively.
It should be clear by now that Bubble was doing a lot of things for you. But you can also do the same as long as you know what you need to do on your own.
Automatic daily backups
You need to configure backups, mostly automatic on managed databases
DDoS protection
Usually it's handled by your hosting or CDN, once set up
SSL certificate renewal
It's again automatic, but you need to confirm it once
CDN
You set it up once with Cloudflare
Autoscaling
You choose a host that does it, or you tune it
Log retention
You can choose your own logging setup
Compliance (SOC 2 etc)
It largely depends on your database provider. It is again a one-time setup
The reason to list them is not to scare you off. It’s so that “we need to set up backups” is something you’ve planned.
You can choose React, Next.js or any other frontend framework. All AI agents know all the frameworks.
With AI agents writing most of the code, the cost of a given stack choice is lower than it used to be. Although LLMs tend to favour and are good at React and Next.js.
You should always focus on the backend. Your database, your auth, and your core API are the foundation on which everything is built.
Building them first lets you confirm that your data is intact. If I have to recommend an LLM for this, choose Codex. It’s good at backend and data-heavy operations.
Focusing on the frontend first works when the UI is the issue, and you can connect a new frontend to Bubble’s existing Data API. You can start replacing the app module by module while the Bubble serves as the backend.
I recommend working on the migration module by module. Pick a single module and build it all the way through, database, API, and UI, from top to bottom.
This way you will learn a lot about where things went wrong for you, because they will, before you have committed to migrating everything.
Whichever you pick, choose your first module by the same logic: lowest dependencies.
Map out which other modules depend on it before you start. Leave the most interconnected module for when the foundations are solid.
Jumping into the hardest task first will cause you trouble.
If you start building pages without a system, you get the thing everyone recognises as an AI-generated app.
The fix is a design system. This means your colours, spacing, and typography. Then components are built from those tokens, the buttons, cards and inputs. Then, the pages are assembled from components.
If you build it in that order, consistency is automatic. But if you build pages first, your app will never look consistent.
If you have designs in Figma, you can connect Figma directly to Claude Code and Codex, so the agent builds UI.
Claude is better than Codex when it comes to frontend. Have the agent take a screenshot of what it built using Playwright, and review it. This dramatically improves the output in UI.
Getting away from the default look is mostly about experience, rather than accepting the first thing the AI agent builds. This is where having someone with taste is the difference between “looks like a template” and “looks like a product.”
The backend build is mostly a translation exercise from the documentation you produced earlier. Each Bubble workflow will now be an API endpoint.
First, re-implement Privacy Rules. Every rule you audited earlier becomes server-side logic and row-level security. Do not let the agent assure you it “added security.” Verify that each specific rule from your audit exists and works. Agents will sometimes claim something is working when it isn’t.
Second, start the data migration. Import the cleaned data into the new schema, run the file-rehosting process, and then validate that record counts match. Count the records in the old system, count them in the new one, and confirm they match.
And lastly, move scheduled and background work. Bubble’s scheduled API workflows should be converted to cron jobs or queue workers.
You’re probably going to use Claude Code or Codex to help with the migration. If not, I highly recommend you do so, and you need to do a few things to ensure the agents are effective.
CLAUDE.md is a file where you write instructions and rules for Claude Code. It works as a guide that tells Claude how your project operates, which coding standards to follow, and what you want it to remember about your preferences.
It loads at the start of every session and helps Claude make better decisions about your code. Split domain-specific rules into separate files that load only when relevant.
Then, structure the repo so that the frontend and backend are separate, because it will make parallel agents possible. If the boundaries are clear, two agents can work without stepping on each other.
The documentation you created earlier now becomes your product requirements, broken into small, complete vertical slices.
Use Git from day one. It will help you create branches and commits, and retain the full history. This is your safety net. When an agent makes a change you don’t like, git is how you undo it cleanly.
LLMs are improving every day, but they still make mistakes. Without version control, you’re putting your entire project at risk.
Claude Code is good at frontend and UI work. Codex is good at backend-heavy, database work. So the easiest split is along the frontend-backend tasks.
And build with one agent (Claude or Codex), then have the other do an adversarial review of the result. Codex’s review mode is good at this. One agent writes, the other reviews it, and you get better code than either would produce alone.
Keep contexts separate. Don’t give both agents the same information. Focus each agent on its specific area to improve performance. A backend agent does not need to know your CSS rules.
You can run both agents at once using a terminal that splits into panes, with tmux or zellij, or by pointing each agent at a separate directory, or with git worktrees, which let agents work without merge conflicts.
Keep a shared task list and explicitly mark dependencies, so one agent does not start work that depends on something the other has not finished. Check git status constantly. Review changes before they are committed. And never let two agents edit the same files simultaneously.
Quality will suffer if the tasks are not clearly defined. If you give agents unclear tasks, they might take on overlapping roles and end up creating parts that don’t work well together. So always give specific and well-defined tasks.
You need a safety net that runs for every change that LLM agents do, without anyone remembering to trigger it. That’s what these gates are.
Pre-commit hooks run automatically before any code gets committed. Formatters, linters, secret scanners so an API key never gets committed by accident, and basic tests.
You can automate the correctness checks so they happen before code ever reaches review. Linting and formatting config gives the agents a consistent style to follow, which keeps the codebase readable even when different agents wrote different parts.
Continuous integration makes sure that your code meets the definition of done by making sure it is executable. If tests must pass before deployment, the issue of “it works on my machine” is eliminated, as CI will run the same checks every time.
Always test the output of the agents before you push it to product. Reviewing is faster than re-running everything yourself, and it works even for sessions you weren’t watching. Better still, have a second agent with fresh context try to find gaps in the first agent’s work. The agent who did the work should not be the one grading it.
Everyone is hyping up AI coding. They’re excellent at generating code fast, working across many files, handling well-defined tasks, and following clear conventions. Use them for all of that. But don’t depend on them for business logic.
They can have small, easily overlooked errors, and poorly designed tests may fail to identify them. They also have a tendency to claim that protection measures are in place, such as stating an authorization rule was added when it wasn’t, or that a Privacy Rule exists when there is none.
If you don’t review and share feedback they’d prefer to use the convenient library, not the right one, because an AI agent optimises for getting the task done rather than for the best long-term choice.
AI agents help you with migrating Bubble apps. They don’t replace knowing what correct looks like. A team that understands what “correct” looks like works much faster. A team that does not understand will quickly end up with a broken, unreliable app.
A lot of people will tell you to just hire an agency at this point. I’ll just say that the gap between a fast AI agent and knowing when something’s off is why having experienced help pays off. Whether it’s us or someone else, don’t let agents be the ones grading their own work.
Once you have migrated, you now need to maintain it. You can hire an engineer, retain the agency that built it, or use Claude or Codex if the product is simple. Any of these is fine.
Your old Bubble bill was simple. Bubble plan, plus Workload Unit overages when usage spiked. But now your new bill has a couple of more vendors. Hosting, a database, object storage for files, an auth provider, an email service, monitoring, and a domain.
At first, your costs go up. But as your app grows, it becomes cheaper than Bubble, especially for high-usage apps. The payoff isn’t just lower monthly costs. You end up with a faster app and an asset you fully own.
This list will feel like overkill until one of these happens to you.
Ready to plan your migration?
Most rebuilds run $15k to $25k over three to five months. We'll scope yours in one call. And if a partial migration is all you need, that's what we'll tell you.
Let's talk
Book a relaxed 30-minute call. Bring whatever you're wondering about and we'll help you think it through, whether or not you ever work with us.
Continue reading
Learn why internal tools fail as teams grow past 50 people, and the architecture and process fixes that prevent recurring breakdowns.
Learn how to identify which business processes need automation. Use the "Three People Rule" and "We Tried a Tool" to find high-ROI automation opportunities.
SAP and NetSuite are built for companies ten times your size. Here's why a $12,000 custom tool fixes more than a $150,000 ERP, and how to know which one you actually need.