Toluwalope AkinkunmiLoading…

Sketching things…

000
Skip to content
← All notes

· 2 min read

Share logic, not screens

What went into the shared package between Circular Ticket's Next.js and Expo apps, what stayed out, and why.

Circular Ticket started as a web app. When the mobile app arrived, the fastest path was to copy the API calls and rules across. Within weeks the two apps disagreed about small, important things: how to format a naira amount, which order statuses count as paid, when an organiser can request a payout.

One package, three rules

Both apps moved into an npm-workspaces monorepo with one shared package. It follows three rules:

  • Share what has to agree: API services, query hooks, validation schemas, currency formatting, status mapping and business rules like payout eligibility.
  • Don't share screens. Each app's interface stays native to its platform, so neither feels like a port of the other.
  • No platform imports in shared code. If a module needs the DOM or a native API, it doesn't belong in the package.
Two apps, one shared package.Attendees & organisers → Web app; Attendees & organisers → Mobile app; Web app → Shared package; Mobile app → Shared package; Shared package → Platform API; Platform API ↔ PayoutsAttendees & organisersWeb appNext.jsMobile appExpoShared packagenpm workspacesPlatform APIRESTPayoutsStripeimportsimportstyped requests
Two apps, one shared package.

The hard part is dependencies

The code moved easily. The versions didn't. React, TanStack Query and the validation library have to resolve to the same versions for both apps, and package hoisting behaves differently for Next.js and Metro. Versions are aligned in one place, and lockfile changes get checked in review.

Was it worth it?

Yes. A change to when a payout can be requested now happens in one file, and both apps get it. Web and mobile can't disagree about money any more, and that alone paid for the move.

Related case study

Circular Ticket
Next noteOne sign-in for many appsHow The Circular Net's products moved onto a single OAuth 2.0 sign-in service, and the rules that keep it safe.