Full Stack • Java • System Design • Cloud • AI Engineering

Core Banking System Design Interview Guide

Design a modern core banking system for system design interviews. Covers requirements, architecture, ledger design, transaction processing, APIs, data model, consistency, security, scalability, observability, and trade-offs.

A core banking system is the source of truth for a bank's customers, accounts, balances, ledger entries, and money movement. In a system design interview, this problem tests whether you can design for correctness, consistency, auditability, security, and high availability.

Unlike social feeds or media systems, a banking system cannot treat data loss or duplicate processing as a minor issue. Money movement must be precise, traceable, reversible through controlled accounting entries, and compliant with financial regulations.

Interview Scope

In an interview, keep the scope clear. A full bank includes cards, loans, trading, fraud, statements, AML, branch operations, mobile apps, and regulatory reporting. For a 45 to 60 minute design interview, focus on the core banking platform:

  • Customer and KYC profile management
  • Account opening and account lifecycle
  • Balance inquiry
  • Deposits and withdrawals
  • Internal transfers between accounts in the same bank
  • External transfer initiation
  • Ledger and transaction history
  • Notifications and audit trails

Out of scope unless the interviewer asks:

  • Credit card authorization network
  • Full loan origination workflow
  • ATM hardware protocol
  • Real-time fraud ML platform
  • Investment and trading systems
  • Full regulatory reporting engine

Requirements

Functional Requirements

The system should support:

  • Create and manage customers
  • Complete KYC verification before account activation
  • Open checking, savings, and business accounts
  • Freeze, close, or reactivate accounts
  • Check available and current balance
  • Deposit money into an account
  • Withdraw money from an account
  • Transfer money between two internal accounts
  • Initiate external bank transfers
  • Generate transaction history and account statements
  • Send transaction notifications
  • Maintain complete audit logs

Non-Functional Requirements

The system must provide:

  • Strong consistency for ledger writes and account balances
  • No double debit or double credit for retried requests
  • High availability for read operations and channel access
  • Low latency for balance inquiry and internal transfers
  • Complete auditability for every financial operation
  • Encryption in transit and at rest
  • Fine-grained authorization for customers, employees, and services
  • Disaster recovery with strict RPO and RTO
  • Regulatory compliance, including KYC, AML, PCI where applicable, and data retention

Capacity Estimates

Use rough numbers to show structured thinking:

Metric Estimate
Customers 50 million
Accounts per customer 2
Total accounts 100 million
Daily balance reads 300 million
Daily transactions 50 million
Peak transaction rate 5,000 to 10,000 TPS
Ledger entries per transaction 2 or more
Daily ledger entries 100 million plus
Retention 7 to 10 years or more

Balance reads are much higher than writes. Ledger writes are lower volume but require stronger correctness guarantees.

Core Concepts

Account

An account represents a financial container owned by a customer. It has an account number, product type, status, currency, branch, and balance state.

Ledger

The ledger is an immutable record of debits and credits. It is the most important data structure in the system. Account balances should be derived from or reconciled with ledger entries.

Transaction

A transaction represents a business operation such as deposit, withdrawal, transfer, fee, reversal, or interest credit.

Double-Entry Bookkeeping

Every money movement should create balanced ledger entries. If one account is debited, another account or internal settlement account is credited.

Example internal transfer:

Entry Account Direction Amount
1 Sender account Debit 100
2 Receiver account Credit 100

The sum of debits and credits must balance.

High-Level Architecture

flowchart TD
    Mobile["Mobile App"] --> Gateway["API Gateway"]
    Web["Web Banking"] --> Gateway
    Branch["Branch System"] --> Gateway
    ATM["ATM Channel"] --> Gateway

    Gateway --> Auth["Auth and Authorization Service"]
    Gateway --> Customer["Customer Service"]
    Gateway --> Account["Account Service"]
    Gateway --> Txn["Transaction Service"]

    Txn --> Ledger["Ledger Service"]
    Txn --> Limit["Limit and Risk Service"]
    Txn --> Idem["Idempotency Store"]
    Ledger --> LedgerDB[("Ledger Database")]
    Account --> AccountDB[("Account Database")]
    Customer --> CustomerDB[("Customer Database")]

    Ledger --> Events["Event Bus"]
    Events --> Notification["Notification Service"]
    Events --> Statement["Statement Service"]
    Events --> Audit["Audit and Compliance"]
    Events --> Reconciliation["Reconciliation Service"]

    Txn --> External["External Payment Rails"]

Main Services

API Gateway

Responsibilities:

  • Route requests from mobile, web, ATM, and branch channels
  • Enforce TLS, request size limits, and rate limits
  • Validate authentication tokens
  • Add correlation IDs for tracing

Auth and Authorization Service

Responsibilities:

  • Authenticate customers and employees
  • Enforce MFA for sensitive operations
  • Authorize account access
  • Support roles such as customer, teller, branch manager, auditor, and admin

Customer Service

Responsibilities:

  • Store customer profile
  • Track KYC status
  • Manage customer risk classification
  • Link customers to accounts

Account Service

Responsibilities:

  • Open and close accounts
  • Store account metadata and status
  • Provide balance views
  • Enforce account-level restrictions such as freeze, debit block, or credit block

Transaction Service

Responsibilities:

  • Validate transfer requests
  • Check idempotency key
  • Check limits and account status
  • Coordinate ledger posting
  • Return transaction status

Ledger Service

Responsibilities:

  • Create immutable ledger entries
  • Enforce double-entry balancing
  • Maintain transaction status
  • Guarantee atomic debit and credit posting
  • Provide ledger history for reconciliation and audit

Notification Service

Responsibilities:

  • Send SMS, email, and push notifications
  • Consume transaction events asynchronously
  • Avoid blocking the main transaction path

Reconciliation Service

Responsibilities:

  • Compare ledger, balance snapshots, external payment rails, and settlement files
  • Detect mismatches
  • Produce exception reports
  • Trigger manual or automated repair workflows

Data Model

Customer

Field Notes
customer_id Unique customer identifier
name Legal name
phone Verified phone number
email Verified email
kyc_status pending, verified, rejected
risk_level low, medium, high
created_at Audit field

Account

Field Notes
account_id Internal unique ID
account_number Customer-facing account number
customer_id Owner
account_type checking, savings, business
currency USD, INR, EUR
status active, frozen, closed
current_balance Posted balance
available_balance Balance available for spending
version Used for optimistic concurrency
created_at Audit field

Transaction

Field Notes
transaction_id Unique transaction ID
idempotency_key Client-provided retry key
type deposit, withdrawal, transfer, reversal
status pending, posted, failed, reversed
source_account_id Nullable for cash deposits
destination_account_id Nullable for withdrawals
amount Decimal, never floating point
currency Transaction currency
created_at Request time
posted_at Ledger posting time

Ledger Entry

Field Notes
ledger_entry_id Unique entry ID
transaction_id Parent transaction
account_id Account affected
direction debit or credit
amount Positive decimal
balance_after Optional but useful for fast statements
created_at Immutable timestamp

API Design

Create Account

POST /v1/accounts
Authorization: Bearer <token>
Content-Type: application/json

{
  "customerId": "cust_123",
  "accountType": "CHECKING",
  "currency": "USD"
}

Get Balance

GET /v1/accounts/{accountId}/balance
Authorization: Bearer <token>

Response:

{
  "accountId": "acc_123",
  "currency": "USD",
  "currentBalance": "1250.75",
  "availableBalance": "1200.75",
  "asOf": "2026-07-04T12:30:00Z"
}

Internal Transfer

POST /v1/transfers
Authorization: Bearer <token>
Idempotency-Key: 7f0d8e6a-61f2-4c7a-94cb-12a2d7cbd9d0
Content-Type: application/json

{
  "fromAccountId": "acc_sender",
  "toAccountId": "acc_receiver",
  "amount": "100.00",
  "currency": "USD",
  "description": "Rent payment"
}

Response:

{
  "transactionId": "txn_789",
  "status": "POSTED"
}

Internal Transfer Flow

sequenceDiagram
    participant Client
    participant Gateway
    participant Txn as Transaction Service
    participant Idem as Idempotency Store
    participant Account as Account Service
    participant Ledger as Ledger Service
    participant Events as Event Bus

    Client->>Gateway: POST /v1/transfers
    Gateway->>Txn: Forward request
    Txn->>Idem: Check idempotency key
    Idem-->>Txn: Not processed
    Txn->>Account: Validate accounts and status
    Account-->>Txn: Accounts valid
    Txn->>Ledger: Post debit and credit atomically
    Ledger-->>Txn: Transaction posted
    Txn->>Idem: Save response for key
    Txn->>Events: Publish TransactionPosted
    Txn-->>Gateway: POSTED
    Gateway-->>Client: 200 OK

Consistency and Transaction Handling

For internal transfers, debit and credit should be committed atomically. The simplest approach is to use a relational database transaction inside the ledger boundary:

  1. Validate idempotency key.
  2. Lock accounts in deterministic order to avoid deadlocks.
  3. Check account status and available balance.
  4. Insert transaction row.
  5. Insert debit ledger entry.
  6. Insert credit ledger entry.
  7. Update account balances.
  8. Commit.
  9. Publish event using the outbox pattern.

Use row-level locking or optimistic concurrency depending on throughput and contention.

For high-contention accounts, such as settlement accounts, partition by account or use a dedicated ledger posting queue.

Idempotency

Banking APIs must handle retries safely. A mobile app, API gateway, or network layer may retry after a timeout. Without idempotency, the same transfer could be posted twice.

Design:

  • Require an Idempotency-Key for money movement APIs
  • Store key, request hash, status, and response
  • If the same key is retried with the same request, return the original response
  • If the same key is retried with a different request body, reject it
  • Expire keys after a safe retention window, such as 24 to 72 hours

Database Choice

Use a relational database for the core ledger because it provides:

  • ACID transactions
  • Strong constraints
  • Row-level locking
  • Mature backup and recovery
  • Powerful reporting and reconciliation support

Common choices:

  • PostgreSQL
  • Oracle
  • MySQL with strict transaction configuration

Use NoSQL or search stores for secondary workloads:

  • Elasticsearch or OpenSearch for transaction search
  • Redis for short-lived cache and rate limits
  • Data warehouse for analytics
  • Object storage for statements and reports

Scaling Strategy

Read Scaling

  • Use read replicas for statements and transaction history
  • Cache customer profile and account metadata
  • Cache balance only with very short TTL or event-driven invalidation
  • Use CQRS for heavy statement queries

Write Scaling

  • Partition ledger by account ID or account shard
  • Keep all entries for one account in the same shard when possible
  • Use deterministic account locking
  • Use asynchronous processing for notifications, statements, and analytics
  • Use outbox events to avoid losing domain events after database commit

Sharding

Sharding options:

Strategy Pros Cons
By account_id Good account locality Cross-account transfers may span shards
By customer_id Easy customer view Business accounts with many users can become hot
By branch/region Operationally familiar Uneven load and harder global access
By ledger partition Scales writes More complex reconciliation

For interviews, start with a single strongly consistent ledger database, then discuss sharding as scale increases.

External Transfers

External transfers are more complex because another bank or payment network is involved. They usually cannot be completed in one local ACID transaction.

Use a state machine:

stateDiagram-v2
    [*] --> Received
    Received --> Validated
    Validated --> Debited
    Debited --> SentToPaymentRail
    SentToPaymentRail --> Settled
    SentToPaymentRail --> Failed
    Failed --> ReversalPosted
    Settled --> [*]
    ReversalPosted --> [*]

Use saga-style orchestration:

  • Debit customer account locally
  • Send payment instruction to payment rail
  • Wait for settlement or rejection
  • Post settlement entry or reversal entry
  • Notify customer

Never delete or mutate old ledger entries. Fix financial errors with compensating entries.

Security

Security is a core design requirement, not an add-on.

  • Use TLS everywhere
  • Encrypt sensitive data at rest
  • Tokenize account numbers where possible
  • Use MFA for login, beneficiary setup, and high-risk transfers
  • Apply least-privilege service-to-service access
  • Use HSM or KMS for key management
  • Keep complete audit logs for employee actions
  • Add device fingerprinting and risk scoring
  • Rate limit sensitive endpoints
  • Mask account numbers in UI and logs

Observability

Track both technical and financial signals:

  • API latency and error rate
  • Transaction success and failure rate
  • Ledger posting latency
  • Idempotency conflict count
  • Account lock wait time
  • Event publishing lag
  • Reconciliation mismatch count
  • External rail timeout rate
  • Notification delivery rate

Every request should have:

  • Correlation ID
  • Customer ID or anonymized customer reference
  • Transaction ID
  • Idempotency key
  • Channel ID

Do not log sensitive account numbers, tokens, or personal data in plain text.

Failure Scenarios

Failure Handling
Client retries transfer after timeout Return stored idempotent response
Notification service is down Transaction still succeeds; notification retries asynchronously
Event bus is down Use outbox table and publish later
Debit succeeds but credit fails Avoid this with atomic ledger transaction for internal transfers
External payment rail times out Mark pending and reconcile later
Read replica is stale Use primary or strongly consistent read for critical balance
Data center failure Fail over using tested DR plan

Trade-Offs

Strong Consistency vs Availability

For ledger writes, choose consistency over availability. It is better to reject or delay a transfer than to corrupt balances.

For reads, the system can use replicas and caches, but clearly distinguish between current balance and eventually consistent views.

Microservices vs Modular Monolith

A bank can start with a modular monolith for core ledger logic to keep transactions simple. As scale and teams grow, split services around stable domain boundaries.

Good service boundaries:

  • Customer
  • Account
  • Ledger
  • Transaction orchestration
  • Notification
  • Statement
  • Reconciliation

Avoid splitting debit and credit into separate services if it makes atomicity harder.

Derived Balance vs Stored Balance

Computing balance from all ledger entries is correct but slow. Storing balance is fast but must be kept consistent.

Common approach:

  • Ledger entries are immutable source of truth
  • Account table stores current balance for fast reads
  • Reconciliation jobs verify stored balances against ledger entries

Interview Walkthrough

Use this structure in a system design interview:

  1. Clarify scope: internal transfers, accounts, balance, ledger, statements.
  2. State key non-functional requirements: consistency, auditability, security, availability.
  3. Estimate customers, accounts, TPS, and ledger volume.
  4. Draw the high-level architecture.
  5. Deep dive into ledger and double-entry bookkeeping.
  6. Explain internal transfer flow with idempotency.
  7. Discuss database choice and transaction isolation.
  8. Cover scaling, sharding, and read replicas.
  9. Cover failure handling and reconciliation.
  10. Finish with trade-offs.

Common Interview Mistakes

  • Treating balance as a simple number without a ledger
  • Using floating point numbers for money
  • Ignoring idempotency
  • Updating sender and receiver balances in separate transactions
  • Allowing services to directly write each other's databases
  • Not discussing audit logs
  • Not separating internal transfers from external payment rails
  • Overusing async processing for operations that require atomic consistency
  • Ignoring account locks, frozen accounts, and limits

Final Design Summary

A strong core banking design should use:

  • API Gateway for all banking channels
  • Auth service with MFA and authorization
  • Customer service for profile and KYC
  • Account service for account lifecycle and balance view
  • Transaction service for orchestration
  • Ledger service as the source of truth
  • Relational database for ACID ledger writes
  • Idempotency store for safe retries
  • Outbox pattern for reliable events
  • Event bus for notifications, statements, audit, and reconciliation
  • Reconciliation jobs for financial correctness
  • Strict security, observability, and disaster recovery controls

The most important interview point is this: in banking, correctness beats convenience. Design the ledger first, then build channels, APIs, caches, and analytics around it.