The short version

Published architecture guides variously describe three, four and five layers, and they are all defensible, because the layer count is a drawing convention rather than a design. The decision that actually shapes a banking app is where the system of record ends. That boundary determines what the app may cache, what it must ask for every time, which component enforces a limit, and who is right when two of them disagree. Most weak designs are weak in one specific way: they let an answer be owned one zone too far forward, usually on the handset.

If you read five guides on mobile banking architecture you will get five different diagrams, and the thing they disagree about is how many boxes to draw. That disagreement is a clue. The number of layers is not what distinguishes a design that survives contact with a bank from one that does not.

What distinguishes them is whether each answer has exactly one owner, and whether that owner is on the right side of the line.

The only boundary that matters

A bank has a system of record. It holds the balances, the postings, the limits, the entitlements and the mandates. It is usually older than the app by decades, it is usually the thing an auditor will ask about, and it is the component that is right by definition when anything disagrees with it.

Everything you build is a channel onto that. That is not a diminishment; it is the constraint that makes the design tractable. Once you accept it, a surprising number of arguments resolve themselves, because the question stops being "where should this logic go?" and becomes "who owns this answer?"

Three zones, then, and the useful discipline is to put every feature in exactly one of them.

THREE ZONES, ONE OWNER PER ANSWER ZONE OWNS MUST NEVER OWN THE DEVICE you cannot patch it fast presentation, navigation session state, cached reads balance truth, limits entitlements THE CHANNEL LAYER where arguments belong aggregation, orchestration 2FA policy, response shape the ledger the final word THE SYSTEM OF RECORD right by definition balances, postings, limits entitlements, mandates any knowledge of your screens EVERY FEATURE BELONGS IN EXACTLY ONE ROW BAD DESIGNS PUT THE ANSWER ONE ROW TOO HIGH
The row count is not the point; single ownership of each answer is.

The channel layer is where the arguments go

Call it a backend for frontend, a channel layer, a digital platform, or — if the bank runs Oracle — the thing OBDX already is. The name varies; the job does not.

It exists because a single account screen may need a balance, recent transactions, card status and a pending approval, and in a bank those are four systems with four interfaces, four availability profiles and four teams. Something has to compose them into one answer. If that something is not a server you control, it is the app — and now orchestration logic lives on a device you cannot patch for days.

This layer is also where the awkward decisions belong: which second factor applies to which transaction, how to behave when one upstream is slow, what a partial failure looks like to a user, how to express a limit breach as something a human understands. All of these are genuinely contested, all of them change, and all of them are cheap to change in one place and expensive to change in an app store.

One caution on the common advice to run a separate backend for frontend per platform. It is occasionally right, and usually it is two codebases drifting apart until iOS and Android quietly enforce different rules. Prefer one channel layer until you can name the divergence that justifies a second.

What the client is allowed to decide

Nothing that affects money or entitlement.

The app decides what to show, in what order, and when to ask. It does not decide whether a transfer is within limits, whether this user may see that account, or whether a step-up is required. Those feel like client decisions because the client is where they are displayed, and that is exactly the confusion to watch for.

The rule is simple: a control enforced only on the device is enforced nowhere, because the device is the one component an attacker fully controls. Client-side checks are a courtesy to the user — fail fast, don't waste a round trip — and the server must behave identically if they are absent. If your API would accept a transfer that your app would have blocked, you do not have a limit, you have a label.

The same logic drives something easy to get backwards: an authorisation prompt should be raised by the server because the transaction happened, not requested by the client because it thinks one is due. We described how OBDX does exactly this with push — the transaction triggers the notification. A compromised client can decline to ask for a prompt. It cannot decline to receive one.

Where authentication sits

Across the line, always, and usually further back than people expect. The identity provider is typically not the banking application at all but a separate system the bank already runs, with the channel layer exchanging credentials for tokens rather than holding them. We set this out in more detail for Oracle's stack specifically, but the shape is general.

What the device holds is a token with a bounded lifetime and a device registration, not a credential. The practical consequence: if a handset is lost, the control that matters is server-side revocation of that session and that registration. Anything that depends on the app cooperating is not a control.

The question that tests a design

Ask what the app shows when the core is unreachable. It is a short question and it exposes the whole architecture.

A design that has thought it through has specific answers. Balances are shown from cache, labelled with when they were retrieved. Transfers are refused outright rather than queued, because a queued payment creates an obligation nobody agreed to. The difference between "we cannot reach your bank right now" and "you have no transactions" is visible to the user, because those are very different facts.

A design that has not thought it through fails in one of two ways. Either the whole app is unusable the moment one upstream hiccups, which is a bad experience. Or — far worse — stale figures render exactly like live ones, and a customer makes a decision on a number that was true yesterday. The first costs you complaints. The second costs you a regulatory conversation.

This is also why core availability shapes a mobile programme more than any framework choice. The integration is the architecture, which is the argument we make at greater length in what actually connects to what.

What an architecture review should ask

  1. For each screen, which zone owns each number on it? If two zones could answer, the design has a defect that will surface as a support ticket about a wrong balance.
  2. Which checks exist only on the client? Then assume the client is hostile and ask what happens.
  3. What does the app do when each upstream is down, individually? Not "the backend" — each one.
  4. How is stale data distinguished from live data, in the interface, not in the code?
  5. What is revoked, server-side, when a device is lost?
  6. Can the core and the app be released independently? If not, every core upgrade becomes an app release, and the schedule belongs to someone else.

None of these mention a layer count, and that is the point. A diagram with the right number of boxes and the wrong ownership is a worse artefact than a rough sketch where every answer has one home.

Questions we get asked

How many layers should a mobile banking app have?

The count is a drawing convention, which is why published guides variously say three, four and five and all of them are defensible. What matters is that three responsibilities are separated: the device presents, a channel layer orchestrates and enforces policy, and a system of record holds the truth. Whether you draw the channel as one box or three changes nothing about the design.

What is a backend for frontend in a banking app?

A service that sits between the app and the bank's internal systems and returns responses shaped for a screen rather than for a domain. It exists because a single account view may need balances, recent transactions, card status and pending approvals, which in a bank are four different systems. Without it the app performs the aggregation, which puts orchestration logic on a device you cannot patch quickly.

Should the mobile app talk to core banking directly?

No. A core banking system is not designed to be addressed by thousands of handsets, its interfaces are not shaped like screens, and exposing it directly makes every core upgrade an app release. A channel layer between them is what allows the core and the app to change on separate schedules, which over a product's life matters more than any single design decision.

What should the app itself be allowed to decide?

Nothing that affects money or entitlement. The client decides presentation, navigation and when to ask. It must not decide whether a transfer is within limits, whether a user may see an account, or whether a second factor is required. Any of those enforced only on the device is enforced nowhere, because the device is the one component an attacker controls.

Where should push notifications for authorisation originate?

From the server side, triggered by the transaction, not requested by the client. If the app asks for its own second-factor prompt, a compromised client can simply not ask. Making the channel layer raise the prompt means the approval step cannot be skipped by anything running on the handset.

What is the best test of a banking app architecture?

Ask what the app shows when the core is unreachable. A design that has thought about it answers precisely: cached balances shown with their age, transfers refused rather than queued, and a clear distinction between what is stale and what is unavailable. A design that has not will either show nothing at all or, far worse, show stale figures as though they were live.

Related service Fintech app development Banking apps onto cores that predate them

If you are reviewing an architecture before build, the cheapest hour you will spend is the one that assigns an owner to every number on every screen. That is where we start on banking app projects, because it is the defect class that is almost free to fix on a whiteboard and very expensive to fix in production.