05 · Marketplace · Non-Profits
ShareTalent: migrating a live non-profits marketplace to Bubble's new responsive engine.
Seventeen months as lead dev, zero data loss across the responsive-engine migration of a live non-profits marketplace. ShareTalent connects non-profits with freelancers. When I joined, the app was on Bubble's old responsive engine with live users and live revenue. The migration to the new engine shipped on time and inside budget, mobile responsiveness alongside. The work that followed was a security audit pass, a UI/UX rebuild against the client's Figma, performance optimisation ahead of Bubble's move from capacity-based pricing to Workload Units, and the user-feedback iterations that earned me the rebuild of the next version of the product.
A live marketplace, migrated in place
ShareTalent is a two-sided marketplace that connects non-profits with freelancers who want to work for them. Non-profits post the work, freelancers list their skills and portfolios, payments and contracts run through the platform. I came on as lead developer in January 2024. The app was already live with paying users on Bubble.io’s old responsive engine. The migration to the new engine was the first scope: rebuild every page against the new model, keep the live users and live data and live revenue intact, ship mobile responsiveness alongside, fix the bugs that real customers had been living with.
The engagement stretched to May 2025. Seventeen months as lead developer on a single product, across the migration, a security audit pass, a UI and UX rebuild against the client’s Figma, performance optimisation ahead of Bubble’s pricing migration from capacity-based plans to Workload Units, and the user-feedback iterations that kept the product getting better between the headline pieces of work.
The migration: every page rebuilt against the new responsive model.
The old Bubble responsive engine asked you to lay out pages with absolute percentages and manual breakpoints, and then to fix the layout for narrower viewports by hand for every element. It worked for the desktop view the original developer had targeted, but it was brittle the moment the viewport sized to something the page had not been built for, and it made mobile responsiveness a per-page rebuild rather than a property of the layout.
The new responsive engine inverted the model. Pages compose with row and column containers that handle wrapping, alignment, and minimum and maximum sizes the same way modern CSS flexbox does. Responsive behaviour falls out of the container hierarchy rather than being painted on top of it.
The migration was a page-by-page rebuild. The data types, the workflows, the API connector calls, and the Privacy Rules all stayed put. Every layout was re-derived against the new engine, every element re-bound to the same database fields, every workflow re-tested against the new visual structure. Alongside the migration, I resolved the open bugs live users had been carrying. None of it produced visible new features. All of it determined whether the product would feel modern for the next two years or stay brittle for them.
The freelancer onboarding entry, rebuilt against the new responsive engine. Same data type underneath, new layout primitives above.
The non-profit entry into the same onboarding tree. Two halves of the marketplace, one shared user data type, the wizard branching on role at the first step.
Mobile-responsive, shipped alongside the migration.
The original product was not mobile-responsive. The home page rendered acceptably on a phone, but the rest of the application (onboarding, profile editing, project posting, the dashboards) had been built desktop-first and never finished for mobile. Migrating to the new engine without making the app mobile-responsive at the same time would have left a second migration on the table for later.
Doing both passes together was the right call. Every page rebuilt against the new engine got its mobile layout in the same sitting. Row containers with wrap-on-overflow handled the desktop-to-tablet collapse. Column containers with conditional visibility handled the table-to-card transformations on phones. Image and form elements got min-width and max-width bounds so they sized down without breaking the surrounding flow.
Mobile, after the rebuild. The browse list and the navigation drawer both fall out of the container model rather than being separate phone-only screens.
The security audit: Stripe key, Google Maps key, webhooks, and Privacy Rules.
After the migration stabilised, I ran a security pass across the application. The list of issues in the inherited codebase was longer than I expected. Four matter enough to name:
- The Stripe secret key was leaking through client-side API calls. Not the publishable key (which is designed to be public). The secret key, which Stripe's documentation says must never leave the server. A previous developer had wired Stripe API calls through the Bubble.io API Connector with the call configured to run from the browser, so the secret key was included as a request header on every network call any unauthenticated visitor could read in the network tab. The client had no idea. The fix was moving every Stripe call to a server-side backend workflow that runs from Bubble's server with the secret key kept out of the browser entirely, then rotating the key. This was the most consequential issue in the audit and the one I would not have wanted to find a week later.
- The Google Maps API key was not domain-restricted. The key worked from any origin, which meant anyone could lift it from the page source and run requests on ShareTalent's billing. I restricted the key to the production and staging domains directly in the Google Cloud Console. The key now refuses requests from anywhere else. The cost of the fix was zero. The cost of leaving it was open-ended.
- The Stripe webhook receiver was not validating signatures. The Bubble.io backend workflow that received Stripe events was reading the event payload directly without verifying that Stripe had signed it. A malicious actor with the webhook URL could have posted fake events into the workflow. I added signature verification using the Stripe webhook secret so every incoming event has to prove it came from Stripe before any database write happens.
- Privacy Rules were under-scoped on several data types. Read access on a few data types was wider than the product actually required, with the consequence that any authenticated user could query rows that should have been scoped to their own account. I tightened the Privacy Rules to match the real read-access requirement per data type, and added the missing Current User constraints where they had been omitted.
None of these issues had caused a known incident. All four would have eventually. The discipline of running a security pass after a migration is the kind of audit that does not bill back to the client in features but pays back in incidents that do not happen.
UI and UX, implemented against the client's Figma.
Alongside the migration the client had a Figma file with UI and UX improvements they wanted shipped. Some of it was visual polish, some of it was small interaction redesigns, some of it was new flows the original responsive engine had made too painful to build. The migration to the new engine was the lever that made the Figma work cheap rather than expensive: layouts that would have been per-page hacks on the old engine were properties of the container tree on the new one.
The work was the disciplined kind: pixel-faithful implementation of the Figma where the Figma was definitive, plus the judgment calls about responsive behaviour and edge states that the Figma did not specify. The product team’s design intent landed in the live app without me redesigning it along the way.
The freelancer Categories and Skills step from the Figma. Pill grids like this needed careful min and max widths in the new engine to behave gracefully from a 1440px viewport down to a 360px phone.
The non-profit’s profile setup. The form is short on purpose; the marketplace optimises for the work being posted, not for the profile being a thing of beauty.
Performance optimisation ahead of Bubble's Workload Units pricing.
Around the same period, Bubble.io announced a pricing migration from capacity-based plans to Workload Units, the metered model that charges per workflow execution rather than per app size. Apps that had been comfortable on the old pricing could become surprisingly expensive on the new one if the workflow patterns were inefficient: lazy database reads, ungrounded searches, and unbounded scheduled workflows all show up in the WU bill in a way they did not show up in the capacity bill.
I audited the application’s workflow patterns against the new pricing model. The hottest paths got the standard treatment: server-side database constraints replacing client-side filters, paginated repeating groups replacing “all rows” lists, scheduled backend workflows scoped to actual change windows instead of running on a blanket interval, and the search-index Bubble feature applied where it actually helped instead of on every list by reflex. The app was ready for the pricing migration before the migration arrived, with the cost trajectory under control rather than discovered after the bill jumped.
The freelancer review page. Each section is gated by completion; the ring at the top shows progress across the seven steps.
The non-profit’s review page, the org-side mirror of the freelancer flow. Three core steps plus Billing and Payments, each gated by completion in the same pattern.
Payment settings, where the platform’s economics become legible to the freelancer before they ever pitch.
The ongoing iterations, then the rebuild from scratch.
The headline pieces of work (the migration, the security pass, the Figma implementation, the WU optimisation) anchored the engagement. The work that ran in between them was the steady stream of improvements that came out of real user feedback: small flow adjustments where users were dropping off, copy tweaks where the onboarding language was confusing, fixes for edge cases the testing pass had missed, and the kind of incremental polish that compounds into a product that feels considered.
The next chapter of the engagement was the founder planning a rebuild of the product from scratch on a clean Bubble.io foundation. The version this case study describes has since been retired in favour of that rebuild. The rebuild itself is a separate engagement and a separate case study. What this page is about is the part where, after a careful migration, a thorough security pass, a faithful Figma implementation, and a year of iteration on top, the client trusted me with the next version as well.
Structured intake on the work history step. Every field stays a structured row so the marketplace’s matching surface has clean data to read.
Portfolio items follow the same structured-data pattern. The pill categories drive how a project gets surfaced to the non-profits browsing for talent.
What changed
ShareTalent shipped on the new Bubble.io responsive engine on time and within budget, with the live user base preserved end to end and mobile responsiveness as a side effect of the rebuild. The security audit pass surfaced four issues that mattered (the Stripe secret key leaking through client-side API calls, the unrestricted Google Maps key, the missing webhook signature verification, the under-scoped Privacy Rules) and fixed each one. The Figma-driven UI and UX work landed without redesigning the client’s intent along the way. The Workload Units optimisation pass set the app’s cost trajectory before the pricing migration arrived. The relationship continued past the migration into ongoing development and maintenance.
The version of the product this case study describes has since been retired in favour of a from-scratch rebuild on a clean Bubble.io foundation, which I am the lead engineer on as a separate engagement.
Seventeen months as lead developer on a single product, with the client trusting me with the rebuild on the back of it, is the kind of relationship that does not happen by accident. The pattern of the engagement is the part I would do again. Take the migration scope seriously, do the security pass that nobody specifically asked for, implement the client’s design intent without redesigning it, audit performance ahead of pricing changes that are visible on the calendar, and let the trust compound on the back of careful first work.