# Telegram-iOS Architecture with 100+ Submodules: A Modular Monorepo Deep Dive

> Explore the Telegram-iOS architecture, a Bazel monorepo with 100+ submodules. Learn how isolated Swift & Objective-C sources enable parallel compilation & efficient dependency management.

- Repository: [TelegramMessenger/Telegram-iOS](https://github.com/TelegramMessenger/Telegram-iOS)
- Tags: architecture
- Published: 2026-04-07

---

**Telegram-iOS is built as a Bazel-driven modular monorepo containing over 100 independent submodules, each with isolated Swift/Objective-C sources, public headers, and BUILD files, enabling parallel compilation and fine-grained dependency management between the core engine, feature UI components, and third-party libraries.**

The TelegramMessenger/Telegram-iOS repository represents one of the largest open-source iOS codebases, structured as a highly modular monorepo where functionality is partitioned into more than 100 self-contained submodules. This architecture leverages **Bazel** as its build system to manage complex dependencies between core networking engines, UI feature modules, and native libraries like **sqlcipher** and **rlottie**, ensuring deterministic builds and scalable team collaboration.

## Bazel-Centric Build System and Workspace Structure

According to the Telegram-iOS source code, the repository root contains a `WORKSPACE` file and a top-level `BUILD.bazel` that define external repositories and common build rules. Each submodule ships its own **`BUILD`** file declaring Swift/Objective-C sources, resources, and dependencies, allowing Bazel to treat every feature as an independent library.

In `submodules/CallListUI/BUILD`, the target definition follows this pattern:

```python
swift_library(
    name = "CallListUI",
    srcs = glob(["Sources/**/*.swift"]),
    hdrs = glob(["PublicHeaders/**/*.h"]),
    deps = [
        "//Telegram:TelegramFramework",
        "//submodules/AvatarNode",
        "//submodules/AlertUI",
    ],
    visibility = ["//visibility:public"],
)

```

This configuration enables **deterministic builds** and **parallel compilation**, where Bazel analyzes the dependency graph across all 100+ modules before invoking the compiler.

## The 100+ Feature Submodules Organization

The `submodules/` directory contains over 100 feature-oriented modules, each following a standardized structure to isolate functionality and prevent circular dependencies. As implemented in TelegramMessenger/Telegram-iOS, the typical submodule layout includes:

- `Sources/` — Swift or Objective-C implementation files
- `PublicHeaders/` — C/Objective-C headers exposed to other modules  
- `BUILD` — Bazel target definition specifying dependencies and visibility

Representative submodules include:

- **CallListUI** — UI for the Calls tab (list, edit, delete) located at [`submodules/CallListUI/Sources/CallListController.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/CallListUI/Sources/CallListController.swift)
- **AvatarNode** — Reusable component for rendering user and chat avatars at [`submodules/AvatarNode/Sources/AvatarNode.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/AvatarNode/Sources/AvatarNode.swift)  
- **BrowserUI** — In-app web browser implementation at [`submodules/BrowserUI/Sources/BrowserScreen.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/BrowserUI/Sources/BrowserScreen.swift)
- **BotPaymentsUI** — Payment form UI for bots at [`submodules/BotPaymentsUI/Sources/BotPaymentCardInputItemNode.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/BotPaymentsUI/Sources/BotPaymentCardInputItemNode.swift)
- **ChatPresentationInterfaceState** — Core data structures describing chat UI state at [`submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/ChatPresentationInterfaceState/Sources/ChatPresentationInterfaceState.swift)

This **micro-feature architecture** keeps compile-times manageable and allows separate teams to develop independent pieces without merge conflicts in monolithic files.

## Core Application Layer and Entry Points

The `Telegram/` folder contains the **application entry point**, global services, and Xcode project layout generated by Bazel. Key files include:

- [`Telegram/Telegram-iOS/AppDelegate.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/Telegram/Telegram-iOS/AppDelegate.swift) (generated) — Sets up the `AppContext`, registers global observers, and launches the root `TelegramRootController`
- [`Telegram/NotificationService/Sources/NotificationService.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/Telegram/NotificationService/Sources/NotificationService.swift) — Handles push-notification payloads in a background service  
- `Telegram/BUILD` — Aggregates all feature libraries into the final application bundle

The app's root controller assembles submodule UI components (such as `ChatListController`, `CallListController`, and `AvatarNode`) and injects the shared **AccountContext**, which carries the `Engine` (network, database, media) and `PresentationData` (theme, strings).

## Data Flow: Engine, Presentation, and UI Composition

The architecture enforces strict separation between the engine layer and UI components. According to the source code in [`submodules/CallListUI/Sources/CallListController.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/CallListUI/Sources/CallListController.swift), the data flow operates as follows:

1. **Engine Layer** — `TelegramCore` and `Telegram` frameworks provide low-level APIs for network (`MTProto`), database (`sqlcipher`), and media handling (`libvpx`, `opusfile`)
2. **Feature Submodules** — Import the engine via Bazel `deps` (e.g., `//Telegram:TelegramFramework`) and expose Swift-friendly wrappers  
3. **Presentation Layer** — `PresentationData` and `PresentationResources` from `TelegramPresentationData` pass through `AccountContext` to provide localization and theming
4. **UI Composition** — Each screen is a controller node (`ASDisplayNode`-based) assembling child nodes from other submodules

The `CallListController` demonstrates this pattern by receiving `AccountContext` and delegating actions to `context.engine` rather than containing networking logic directly:

```swift
public final class CallListController: TelegramBaseController {
    private let context: AccountContext
    private var presentationData: PresentationData

    public init(context: AccountContext, mode: CallListControllerMode) {
        self.context = context
        self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
        super.init(context: context,
                   navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData,
                                                                             style: .glass))
    }

    override public func loadDisplayNode() {
        self.displayNode = CallListControllerNode(controller: self,
                                                  context: self.context,
                                                  mode: self.mode,
                                                  presentationData: self.presentationData,
                                                  call: { [weak self] peerId, isVideo in
                                                      self?.call(peerId, isVideo: isVideo)
                                                  })
        self._ready.set(self.controllerNode.ready)
        self.displayNodeDidLoad()
    }
}

```

This separation keeps each submodule **thin**, **testable**, and focused solely on UI presentation.

## Third-Party Library Integration as Bazel Targets

Third-party dependencies reside in `submodules/` and `third-party/`, wrapped as Bazel targets for deterministic integration:

- **sqlcipher** — Encrypted SQLite database engine at [`submodules/sqlcipher/Sources/sqlite3.c`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/sqlcipher/Sources/sqlite3.c)
- **rlottie** — Lottie animation rendering (C++ with Swift bridge) at `submodules/rlottie/LottieInstance.mm`  
- **libvpx** — VP8/VP9 video codec at `third-party/libvpx`
- **opusfile** — Audio codec for voice calls at `third-party/opusfile`

Each library includes a `BUILD` file declaring appropriate C/C++ rules and exporting Swift module maps when necessary, allowing native code to link cleanly against the Swift UI submodules.

## Summary

- **Modular Monorepo** — Telegram-iOS organizes functionality into over 100 self-contained submodules under `submodules/`, each with dedicated `Sources/`, `PublicHeaders/`, and `BUILD` files.
- **Bazel Build System** — The `WORKSPACE` and distributed `BUILD` files enable parallel compilation, fine-grained dependency management, and deterministic builds across the entire codebase.
- **Three-Tier Structure** — The architecture separates **Core** (`Telegram/` app entry), **Features** (100+ submodules), and **Third-Party** libraries (`third-party/`).
- **Clean Data Flow** — The `AccountContext` injects `Engine` (network/storage) and `PresentationData` (theme/localization) into UI controllers, keeping business logic isolated from presentation code.
- **Native Integration** — C/C++ libraries like **sqlcipher** and **rlottie** are wrapped as Bazel targets and consumed by Swift modules through public headers.

## Frequently Asked Questions

### Why does Telegram-iOS use Bazel instead of standard Xcode builds?

According to the Telegram-iOS repository structure, Bazel provides deterministic builds and fine-grained dependency analysis required to compile over 100 submodules efficiently. Standard Xcode project files become unmaintainable at this scale, whereas Bazel's `BUILD` files allow parallel compilation and explicit dependency declaration between the core engine, UI features, and third-party libraries.

### How are the 100+ submodules organized physically on disk?

The submodules follow a strict directory convention within `submodules/<FeatureName>/`, containing `Sources/` for Swift/Objective-C implementation, `PublicHeaders/` for exposed C/Objective-C interfaces, and a `BUILD` file defining the Bazel target. This structure prevents circular dependencies and enables independent development of features like **CallListUI**, **AvatarNode**, and **BrowserUI**.

### What is the role of AccountContext in the Telegram-iOS architecture?

`AccountContext` serves as the dependency injection container that carries the **Engine** (networking, database, media handling) and **PresentationData** (localization, themes) throughout the application. As shown in [`submodules/CallListUI/Sources/CallListController.swift`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/CallListUI/Sources/CallListController.swift), UI controllers receive this context in their initializer to access shared services without hard-coding dependencies, enabling testable and modular UI components.

### How does Telegram-iOS integrate C libraries like sqlcipher into Swift code?

Third-party C libraries reside in directories like `submodules/sqlcipher/` and `third-party/libvpx/`, each wrapped with a Bazel `BUILD` file that declares C/C++ compilation rules and exports a Swift module map. This allows Swift code in feature submodules to import and call native functions directly, such as the encrypted database operations provided by **sqlcipher** at [`submodules/sqlcipher/Sources/sqlite3.c`](https://github.com/TelegramMessenger/Telegram-iOS/blob/main/submodules/sqlcipher/Sources/sqlite3.c).