A company plans a web application and a mobile app. The work is often described as two builds: finish the website, then reproduce it on iOS and Android.

That sounds tidy. It is also where many teams create the same product twice.

The screens are only the visible part. Underneath them sit the rules that decide who can do what, how data changes, what happens when a payment fails, how notifications are sent, and which records must be kept. If those rules are implemented separately for each client, the products begin to disagree.

A customer updates an address on the web, but the mobile app still shows the old one. A discount works in one checkout and not the other. Support staff cannot explain why two users received different results for the same action. Each bug is small. Together they make the product feel unreliable.

The better approach is to treat web and mobile as two ways into one product system.

Share the rules, not necessarily the interface

The strongest boundary is simple: clients present the experience; the backend owns the business rules.

Suppose a field-service product lets technicians accept jobs, record work, attach evidence, and submit an invoice. Whether the technician uses a browser or a phone, the same service should decide:

  • whether the job is still available;
  • which evidence is required;
  • whether the technician is allowed to submit it;
  • how the invoice total is calculated;
  • what happens after submission.

Those decisions should not be rewritten in JavaScript for the web, Swift for iOS, and Kotlin for Android. They belong in an API and domain layer used by every client.

This does not mean pushing all logic onto a server. A mobile app still validates input, manages local state, and may need to work without a connection. It means there is one authoritative place for rules that must stay consistent.

The interfaces should not be identical

Shared product rules do not require identical screens.

A person at a desk has a large display, a keyboard, and time to compare information. A person holding a phone may be outdoors, moving, using one hand, or working with an unreliable signal. Reproducing a dense desktop table on a small screen is not consistency. It is avoidance.

The mobile version may need:

  • a shorter path to the most common action;
  • a camera-first way to capture evidence;
  • larger controls that work with one hand;
  • saved drafts when the connection disappears;
  • fewer decisions on each screen;
  • notifications that return someone to a specific task.

The web version may need bulk actions, comparison views, keyboard navigation, data exports, and wider operational controls.

Both experiences can still belong to the same product. Consistency lives in language, rules, state, and outcome — not in forcing every screen into the same layout.

Decide what offline means before building

Offline support is one of the decisions that changes the whole mobile architecture. It should not be added at the end.

“Works offline” can mean several things:

  • previously loaded information remains readable;
  • a user can draft work and submit it later;
  • the full workflow continues without a connection;
  • several people can edit the same records and reconcile changes later.

Each level is substantially harder than the one before it.

If technicians only need to capture notes and photos in a basement, a local queue that uploads when the signal returns may be enough. If several warehouse workers must update the same inventory while disconnected, the product needs rules for conflicts, ordering, and duplicate actions. That is not a caching detail. It is part of the product.

Write down the offline promise in plain language. Then design the data flow around that promise.

Make the API a product boundary

An API built only to satisfy the first web screens tends to expose screen-shaped endpoints. When mobile arrives, the team discovers that the client needs data in a different order, over a slower connection, with different failure modes. The API either becomes a patchwork or the mobile app makes too many calls to assemble one screen.

A durable API describes the work the product does. It has clear operations, stable identifiers, predictable errors, and an explicit approach to versioning. It does not reveal internal database details simply because they were convenient during the first sprint.

This boundary also improves testing. The team can verify the product rules without driving a browser or tapping through a phone. Web and mobile tests then focus on presentation, device behavior, and the smaller amount of logic that properly belongs in each client.

Plan identity and permissions once

Authentication is often shared while authorization is accidentally duplicated.

Logging in answers who the person is. Authorization answers what that person may do. The second question is where products become complicated: organization membership, account status, job assignment, approval limits, regional restrictions, or records that should only be visible to a particular team.

If each client makes those decisions independently, a hidden button becomes a security boundary. It is not one. A user can call the underlying endpoint without the screen.

The server must enforce permissions for every operation. Clients should also reflect those permissions so people are not invited to attempt actions that will fail. One source of truth, clearly communicated in both experiences.

Release paths are part of the product plan

Web software can be released whenever the team is ready and rolled back quickly. Mobile releases pass through app-store review and remain installed on devices long after a new version is available.

That difference affects backend changes. An API update cannot assume every mobile user has installed the latest client. For a period, sometimes a long one, old and new versions must both work.

Teams should decide early:

  • how long older app versions will be supported;
  • which API changes require a new version;
  • how urgent fixes reach users;
  • what happens when an app is too old to continue safely;
  • how feature releases are coordinated across web, iOS, and Android.

Without this plan, a routine backend change can break a mobile app that was working the day before.

Choose code sharing for the right reason

Cross-platform frameworks can be a good choice. They can reduce repeated interface work and help a small team maintain iOS and Android together. But “one codebase” is not the same as one product system, and it does not remove platform work.

Camera access, notifications, background tasks, secure storage, accessibility, app links, purchases, and operating-system updates still need device-specific attention. A shared framework lowers some costs and introduces its own constraints.

The decision should follow the product:

  • How much of the interface is genuinely shared?
  • Which device capabilities are central to the experience?
  • What skills does the team have?
  • How long must the application be maintained?
  • Is independent platform tuning a competitive advantage or unnecessary expense?

There is no universal correct stack. There is only a stack that fits the product and a team prepared to own it.

What a healthy system looks like

Users should be able to move between web and mobile without wondering which version contains the truth. Actions have the same meaning. Permissions agree. Data arrives in a form each client can use. Mobile handles weak connections deliberately. Older app versions do not break without warning. The interfaces respect their devices instead of imitating each other.

That outcome does not come from maximizing shared code. It comes from sharing the right things: product rules, identity, data contracts, and operational understanding. Once those foundations are common, web and mobile are free to be good at different jobs.

Bring us the rough version.

In 30 minutes, we'll test the scope, name the first risk, and tell you honestly whether we're the right team.

Booking project conversations

Book a 30-minute call

You speak with an engineer. No sales hand-off.