---
title: "Midday Architecture Overview"
description: "Midday's system design — Supabase backend, Hono API, tRPC, banking integrations, and AI pipeline"
image: "https://tractiongrowth.com/og/open-source/midday-ai-finance/architecture/image.png"
---

# Midday Architecture Overview

# Midday Architecture Overview

<Callout title="For Product Managers">
  This page explains *how Midday is structured* as a software system. Focus on the diagrams and "Why It Matters" callouts to understand how bank connections, AI features, and invoicing work under the hood.
</Callout>

Midday uses a distributed services architecture with a Next.js dashboard, a Hono API, Supabase-backed PostgreSQL, and background workers to handle banking, invoicing, and AI-driven workflows. This page explains how those systems connect and why Midday splits product logic across apps, APIs, and async jobs.

## How Midday Architecture Works

Midday uses a **distributed services architecture** — a Next.js dashboard, a Hono API server, and a BullMQ worker, backed by Supabase (managed PostgreSQL).

```
┌──────────────────────────────────────────────────────────────────┐
│                         USERS (Browser / Desktop)                │
└───────────────────────────────┬──────────────────────────────────┘
                                │
               ┌────────────────┼────────────────┐
               │                │                │
    ┌──────────▼──────┐  ┌─────▼──────┐  ┌──────▼───────┐
    │   Dashboard      │  │  Website   │  │  Desktop     │
    │  (Next.js 16)    │  │ (Next.js)  │  │  (Tauri 2)   │
    │  Railway :3001   │  │ Vercel     │  │  macOS app   │
    └────────┬─────────┘  └────────────┘  └──────┬───────┘
             │                                    │
             │  Server Actions + tRPC             │ REST API
             │                                    │
    ┌────────▼────────────────────────────────────▼───────┐
    │                  Hono API (Bun)                      │
    │                  Railway :3003                       │
    │                                                      │
    │  ┌──────────┐  ┌──────────┐  ┌──────────────────┐   │
    │  │  tRPC    │  │  REST    │  │  OpenAPI (Scalar) │   │
    │  │  Routers │  │  Routers │  │  Documentation    │   │
    │  └──────────┘  └──────────┘  └──────────────────┘   │
    └──────┬────────────┬──────────────┬──────────────────┘
           │            │              │
  ┌────────▼───┐  ┌─────▼─────┐  ┌────▼──────────────┐
  │  Supabase  │  │   Redis   │  │  External Services │
  │ (Postgres) │  │  (Cache)  │  │                    │
  │            │  │           │  │ • Plaid (banking)  │
  │ • Auth     │  │ • BullMQ  │  │ • GoCardless       │
  │ • Storage  │  │ • API cache│  │ • Teller           │
  │ • Realtime │  │ • Sessions│  │ • Stripe (payments)│
  │ • 45+ tables│  └─────┬─────┘  │ • OpenAI (AI)     │
  └────────────┘        │        │ • Resend (email)   │
                  ┌─────▼─────┐  │ • Xero/QuickBooks  │
                  │  Worker   │  │ • Typesense        │
                  │  (BullMQ) │  └────────────────────┘
                  │  Railway  │
                  │           │
                  │ • Bank sync│
                  │ • Documents│
                  │ • Inbox    │
                  │ • Invoices │
                  │ • Insights │
                  └───────────┘
```

<Callout type="info" title="Why It Matters">
  The Dashboard handles the UI and server-side rendering. The Hono API is a separate service providing tRPC + REST endpoints for the dashboard, desktop app, and third-party integrations. The Worker processes background jobs (bank sync, document processing, invoice scheduling) via BullMQ. All three services connect to the same Supabase PostgreSQL instance via Drizzle ORM.
</Callout>

## API Architecture: Hono + tRPC

The API server (`apps/api/`) uses **Hono** as the HTTP framework and **tRPC** for type-safe RPC:

```
Hono Server (:3003)
  ├── /trpc/*           → tRPC routers (type-safe, dashboard uses these)
  └── /rest/*           → OpenAPI REST routers (desktop, third-party)
        ├── /transactions
        ├── /invoices
        ├── /customers
        ├── /bank-accounts
        ├── /tracker-projects
        ├── /tracker-entries
        ├── /inbox
        ├── /documents
        ├── /chat
        ├── /insights
        ├── /search
        ├── /reports
        ├── /tags
        ├── /users
        ├── /teams
        ├── /notifications
        ├── /files
        ├── /apps
        ├── /oauth
        ├── /webhooks
        ├── /mcp
        └── /transcription
```

**Auth:** JWT verification via JWKS (Supabase's public key endpoint) with HS256 fallback. Every request extracts `{ user: { id, email, full_name } }` from the token.

**Rate Limiting:** `hono-rate-limiter` — 100 requests per 10 minutes per user.

## Database Architecture

### Supabase + Drizzle ORM

Midday uses **Supabase** (managed PostgreSQL) with **Drizzle ORM** for type-safe queries. The schema is defined in `packages/db/src/schema.ts`.

### Core Entity Groups

**Financial:**

| Table                     | Purpose                                            |
| ------------------------- | -------------------------------------------------- |
| `transactions`            | Bank transactions (amount, date, category, status) |
| `transaction_categories`  | Category assignments                               |
| `transaction_enrichments` | AI-enriched metadata (merchant, logo)              |
| `transaction_attachments` | Linked receipt files                               |
| `transaction_tags`        | Custom tag assignments                             |
| `bank_accounts`           | Connected bank accounts                            |
| `bank_connections`        | Provider connections (Plaid/GoCardless/Teller)     |
| `institutions`            | Bank/institution directory                         |
| `exchange_rates`          | Currency conversion rates                          |

**Invoicing:**

| Table               | Purpose                                           |
| ------------------- | ------------------------------------------------- |
| `invoices`          | Invoice header (number, status, due date, amount) |
| `invoice_products`  | Line items                                        |
| `invoice_recurring` | Recurring invoice schedules                       |
| `invoice_templates` | Custom invoice templates                          |
| `invoice_comments`  | Team collaboration on invoices                    |

**Time Tracking:**

| Table              | Purpose                |
| ------------------ | ---------------------- |
| `tracker_projects` | Projects being tracked |
| `tracker_entries`  | Time log entries       |
| `tracker_reports`  | Time reports           |

**Documents & Inbox:**

| Table            | Purpose                                  |
| ---------------- | ---------------------------------------- |
| `documents`      | Stored files (vault)                     |
| `document_tags`  | Document categorization                  |
| `inbox`          | Incoming receipts/invoices               |
| `inbox_accounts` | Connected email accounts (Gmail/Outlook) |

**Users & Teams:**

| Table           | Purpose                          |
| --------------- | -------------------------------- |
| `users`         | User profiles                    |
| `teams`         | Business entities (tenancy unit) |
| `users_on_team` | Team membership                  |
| `customers`     | Client directory                 |

**AI & Insights:**

| Table                             | Purpose                                       |
| --------------------------------- | --------------------------------------------- |
| `insights`                        | AI-generated financial analysis               |
| `transaction_category_embeddings` | Vector embeddings for categorization          |
| `document_tag_embeddings`         | Vector embeddings for document classification |

## Banking Integration Architecture

The `@midday/banking` package abstracts four providers behind a unified interface:

```
@midday/banking
  ├── PlaidProvider       → US, Canada (Plaid SDK)
  ├── GoCardlessProvider  → EU, UK (REST via xior)
  ├── TellerProvider      → US (mTLS with certificates)
  └── EnableBankingProvider → EU, UK (JWT auth)
```

Each provider implements a common interface:

* `getAccounts()` → list connected accounts
* `getTransactions(since)` → fetch new transactions
* `getBalance()` → current balance
* `disconnect()` → revoke connection

<Callout type="info" title="Why Four Providers?">
  No single banking API covers the world. Plaid dominates the US/Canada market; GoCardless (via Nordigen) leads in Europe; Teller offers a US alternative with mTLS security; EnableBanking fills additional European coverage gaps. The abstraction layer means the rest of Midday's codebase doesn't care which provider supplies the data.
</Callout>

## AI Architecture

Midday uses the **Vercel AI SDK** with multiple model providers:

### AI Tools (Financial Assistant)

| Tool                           | Purpose                                        |
| ------------------------------ | ---------------------------------------------- |
| `get-expenses`                 | Query expense data by category, date, merchant |
| `get-cash-flow`                | Cash in/out analysis over time                 |
| `get-spending`                 | Spending breakdown by category                 |
| `get-burn-rate`                | Monthly burn rate calculation                  |
| `get-forecast`                 | Revenue/expense forecasting                    |
| `get-metrics-breakdown`        | Key financial metrics                          |
| `get-invoice-payment-analysis` | Invoice payment patterns                       |
| `web-search`                   | External data lookup                           |

### AI Pipeline

```
User asks "What's my burn rate this quarter?"
    │
    ▼
AI SDK → selects tool: get-burn-rate
    │
    ▼
Tool executes: queries transactions table via Drizzle
    │
    ▼
Data returned to AI model
    │
    ▼
Model generates natural language response with data
    │
    ▼
Streamed to user via AI SDK React hooks
```

### Document Intelligence

* **Azure Document Intelligence** — OCR for receipt/invoice PDF extraction
* **Google AI embeddings** — Vector embeddings for document classification
* **LangChain** — Document processing pipeline (mammoth, officeparser, unpdf)

## Authentication

| Method             | Details                                                    |
| ------------------ | ---------------------------------------------------------- |
| **Email/Password** | Via Supabase Auth                                          |
| **OAuth**          | Google, GitHub (via Supabase)                              |
| **MFA**            | Multi-factor authentication support                        |
| **API Keys**       | Stored in `api_keys` table for programmatic access         |
| **OAuth Apps**     | Full OAuth 2.0 server (authorization codes, access tokens) |

## What's Next

<Cards>
  <Card title="What Is Midday?" description="Product overview, target users, and the core financial jobs Midday handles." href="/open-source/midday-ai-finance" />

  <Card title="Midday Workflows and Data Flows" description="Bank sync, invoicing, receipt matching, and AI assistant traced end-to-end." href="/open-source/midday-ai-finance/workflows" />

  <Card title="How Midday Is Built" description="Repository structure, build system, dependencies, and deployment." href="/open-source/midday-ai-finance/how-it-is-built" />
</Cards>

