Core Architectural Components of the AppFlowy Project: A Deep Dive into the Flutter-Rust Stack
AppFlowy implements a modular, multi-language architecture that isolates the Flutter UI from a Rust-based core engine via an FFI bridge, using a plugin-based event dispatcher to coordinate domain-specific services for folders, documents, databases, and AI functionality.
The AppFlowy project (AppFlowy-IO/AppFlowy) is structured as a cross-platform workspace application built with a strict separation between presentation and business logic. Understanding the core architectural components reveals how the codebase maintains portability across desktop and mobile platforms while delivering real-time collaborative features.
Overview of the Multi-Layer Architecture
AppFlowy organizes its codebase into distinct layers that communicate through well-defined interfaces. The architecture separates platform-specific UI code from the business logic, enabling the core engine to run independently of the front-end implementation.
The stack consists of three primary layers: the Flutter front-end responsible for rendering, the Rust core engine handling business logic and state management, and the data persistence layer managing local storage and cloud synchronization.
The Flutter Front-End and FFI Bridge
Flutter UI Layer
The presentation layer resides in frontend/appflowy_flutter/ and contains all Dart code for widgets, screens, and user interaction logic. This is the only platform-specific component, handling platform channels and native UI rendering while delegating all data operations to the Rust core.
The FFI Bridge
Communication between Dart and Rust flows through the frontend/rust-lib/dart-ffi/ crate. This bridge marshals data between the two languages, exposing Rust APIs to Flutter and serializing requests into events that the core engine can process.
When a user creates a new document in the UI, the Flutter layer calls into the dart-ffi crate, which forwards the request to the Rust dispatcher for execution.
The Rust Core Engine
AppFlowyCore Entry Point
The central orchestration happens in frontend/rust-lib/flowy-core/src/lib.rs. The AppFlowyCore::new function initializes the entire system, creating the configuration, logger, and background task scheduler.
// flowy-core/src/lib.rs – AppFlowyCore::new
let core = AppFlowyCore::new(config, runtime, stream_log_sender).await;
This entry point loads all domain service managers and establishes the dependency resolution system that wires services together.
Event Dispatcher and Plugin System
The core uses an event-driven architecture to decouple UI calls from business logic implementation. The make_plugins function in frontend/rust-lib/flowy-core/src/module.rs registers all domain services with the AFPluginDispatcher.
// flowy-core/src/module.rs – make_plugins
pub fn make_plugins(
folder_manager: Weak<FolderManager>,
database_manager: Weak<DatabaseManager>,
user_manager: Weak<UserManager>,
document_manager: Weak<DocumentManager>,
search_manager: Weak<SearchManager>,
ai_manager: Weak<AIManager>,
storage_manager: Weak<StorageManager>,
) -> Vec<Box<dyn AFPlugin>> {
vec![
Box::new(FolderPlugin::new(folder_manager)),
Box::new(DatabasePlugin::new(database_manager)),
// … other domain plugins …
]
}
Each plugin implements the AFPlugin trait and handles specific event types, allowing the system to route calls from the FFI bridge to the appropriate service handler.
Domain Services and Business Logic
AppFlowy encapsulates each major feature area in its own crate, following a consistent pattern of trait-based service definitions and dependency resolution.
Folder, Document, and Database Services
The primary domain crates include:
- flowy-folder/: Manages workspace hierarchy and view structures
- flowy-document-pub/: Handles rich-text document editing
- flowy-database-pub/: Manages grid and board views
Each service implements specific traits (e.g., FolderService, DocumentService) defined in their respective *_pub crates. The FolderServiceImpl in frontend/rust-lib/flowy-folder-pub/src/query.rs demonstrates this pattern:
// flowy-folder-pub/src/query.rs
pub trait FolderService: FolderQueryService + FolderViewEdit {}
pub struct FolderServiceImpl {
folder_manager: Weak<FolderManager>,
user: Weak<AuthenticateUser>,
}
impl FolderService for FolderServiceImpl {}
AI and Search Services
Specialized services extend core functionality:
- flowy-ai-pub/: Generates content suggestions and manages embeddings using a local vector database
- flowy-search-pub/: Provides full-text indexing via Tantivy for fast document retrieval
User and Storage Services
- flowy-user-pub/: Handles authentication and user preferences
- flowy-storage-pub/: Manages file attachments and binary data storage
Each service uses a dependency resolver (e.g., FolderDepsResolver, DatabaseDepsResolver) to receive its required dependencies, including the shared AppFlowyCollabBuilder and ServerProvider.
Data Persistence and Collaboration
Collab Integration
Real-time collaborative editing relies on the collab-integrate/ and collab-* crates. The AppFlowyCollabBuilder constructs Collab instances that domain services use for CRDT-based conflict resolution.
All domain services share this collaboration layer, ensuring that changes to folders, documents, and databases merge correctly across concurrent edits.
Local Storage
When operating offline, AppFlowy persists data via flowy-sqlite/ and flowy-storage/. The KVStorePreferences and StorageManager handle local SQLite databases and file system storage, managed through the FileStorageResolver.
Cloud and Server Infrastructure
Server Layer
The frontend/rust-lib/flowy-server/src/ directory contains the ServerProvider, which abstracts the difference between local-only mode and cloud synchronization. This layer supplies the LoggedUser implementation for authentication and manages remote storage adapters.
Background Processing
Task Scheduler
Long-running operations execute through the TaskDispatcher and TaskRunner found in frontend/rust-lib/lib-infra/src/task.rs. Created during AppFlowyCore::init, this system manages periodic tasks like search indexing and cloud uploads without blocking the main thread.
How the Components Connect at Runtime
The startup sequence demonstrates how these architectural components integrate:
- Initialization:
AppFlowyCore::newloads configuration and creates the task scheduler - Dependency Resolution: Resolvers construct services with the
AppFlowyCollabBuilderandServerProvider - Plugin Registration:
make_pluginsregisters all services with theAFPluginDispatcher - UI Integration: Flutter calls Rust through
dart-ffi, which routes events to the appropriate plugin - Data Flow: Services persist changes locally or sync to the cloud via the server layer
Summary
- AppFlowy separates UI and logic using a Flutter front-end and Rust core engine connected via FFI
- The event dispatcher and plugin system in
flowy-coredecouple UI calls from business logic - Domain services (folder, document, database, AI) live in separate crates with trait-based APIs
- Collab integration provides real-time CRDT-based synchronization across all data types
- The server layer abstracts cloud sync while local storage handles offline persistence
- A background task scheduler manages indexing and uploads without blocking user interactions
Frequently Asked Questions
How does AppFlowy handle communication between Flutter and Rust?
AppFlowy uses an FFI bridge located in frontend/rust-lib/dart-ffi/ to marshal data between Dart and Rust. The bridge converts Flutter method calls into events that the Rust AFPluginDispatcher routes to the appropriate domain service, returning results back to the UI asynchronously.
What is the role of the AppFlowyCollabBuilder?
The AppFlowyCollabBuilder constructs Collab instances that power real-time collaborative editing across all domain services. Located in the core integration layer, it ensures that folder structures, documents, and database records use consistent CRDT-based conflict resolution when merging local and remote changes.
How are new features added to the AppFlowy architecture?
Developers create a new crate in frontend/rust-lib/ following the existing service pattern: define traits in a *-pub crate, implement the service with a manager struct, create a dependency resolver, and register a plugin in flowy-core/src/module.rs. The service then becomes available to the Flutter UI through the existing FFI bridge without modifying core infrastructure code.
Does AppFlowy support multiple front-ends beyond Flutter?
Yes. The architecture intentionally isolates all business logic in Rust with a clean trait-based API. While the current implementation uses Flutter for the UI, the core engine could theoretically support alternative front-ends (Tauri, web, or native mobile) by implementing a new FFI layer that calls the same Rust services.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →