What Is BlockSuite and How Does AFFiNE Use It? A Technical Deep Dive
BlockSuite is a modular, framework-agnostic library that provides collaborative editing building blocks, which AFFiNE utilizes as its core editor engine through the @blocksuite/affine package integration.
BlockSuite powers the real-time collaborative editing experience in AFFiNE, the open-source knowledge base and note-taking platform developed by toeverything. This article examines how the AFFiNE repository leverages BlockSuite's architecture to deliver block-based document editing, synchronization, and extensible UI components.
What Is BlockSuite?
BlockSuite is a framework-agnostic library designed for building collaborative, real-time editing applications. It provides a comprehensive set of building blocks—including text editors, lists, embeds, databases, and graphics—along with a powerful extensibility model that enables developers to construct complex document editing experiences.
Core Architecture and Packages
The library is organized into several core packages that work together to provide a complete editing solution:
@blocksuite/store: Manages the document model, block tree structure, and state management using Yjs for real-time collaboration@blocksuite/std: Provides standard UI utilities, command handling, and theBlockStdScopefor editor lifecycle management@blocksuite/affine: A specialized namespace containing AFFiNE-specific block types, UI widgets, and extensions
How AFFiNE Integrates BlockSuite
AFFiNE integrates BlockSuite as its underlying editor engine through the @blocksuite/affine package. This integration spans data modeling, state management, UI rendering, and real-time synchronization across the application.
The @blocksuite/affine Package Structure
The @blocksuite/affine namespace bundles all AFFiNE-specific implementations:
| AFFiNE Area | Blocksuite Component | Purpose |
|---|---|---|
| Document model | @blocksuite/affine/model |
Defines data schema for paragraphs, headings, tables, and embeds |
| State management | @blocksuite/affine/store |
Manages block trees, collaboration via Yjs, and reactive updates |
| Standard UI utilities | @blocksuite/affine/std |
Provides UI scaffolding, command handling, and widget lifecycle |
| Widgets & toolbars | @blocksuite/affine/widgets/* |
Implements floating toolbars, slash-menus, and page-linking widgets |
| Extensions | @blocksuite/affine/ext-loader |
Allows custom block types without modifying core code |
| Themes & icons | @blocksuite/affine/shared/theme |
Supplies styling tokens and SVG icons |
Workspace and Store Management
At the foundation of AFFiNE's integration is the Blocksuite Store instance, which manages the block graph and document collection. In blocksuite/affine/store/src/index.ts, the store implementation handles Yjs-backed document collections that enable real-time collaboration.
AFFiNE creates a DocCollection instance that serves as the workspace container, then initializes individual document stores within this collection. This architecture allows AFFiNE to support multiple documents while maintaining synchronized state across clients.
Editor Host and Block Rendering
The rendering layer relies on BlockStdScope from @blocksuite/affine/std, which wraps a Lit-based EditorHost component. This scope manages the lifecycle of block widgets and coordinates command execution across the editor surface.
Individual block types—such as paragraphs, images, and databases—are implemented as widgets under blocksuite/affine/widgets/*. For example, the toolbar widget in blocksuite/affine/widgets/toolbar/src/toolbar.ts implements the floating formatting toolbar that appears when users select text.
Key Implementation Details
Extension Loader System
AFFiNE extends Blocksuite's capabilities through the extension loader system defined in blocksuite/affine/ext-loader/src/manager.ts. This system supports dynamic registration of custom block types, view extensions, and commands at runtime, allowing applications like AFFiNE to add specialized functionality without modifying the core Blocksuite library.
Real-Time Collaboration Layer
Blocksuite's synchronization layer, integrated through @blocksuite/affine/store, leverages Yjs for conflict-free replicated data types (CRDTs). This enables AFFiNE's real-time collaboration features, allowing multiple users to edit documents simultaneously with automatic conflict resolution.
The sync layer handles binary updates efficiently, transmitting only document deltas rather than full state, which optimizes network usage for AFFiNE's cloud and self-hosted deployments.
Code Examples
The following examples demonstrate how AFFiNE interacts with Blocksuite APIs in practice.
Creating a Blocksuite Store
AFFiNE initializes document storage using the Blocksuite store API:
import { createStore } from '@blocksuite/affine/store';
import { DocCollection } from '@blocksuite/affine/store';
// Initialise a Yjs‑backed collection
const collection = new DocCollection();
const store = createStore(collection);
// Use the store in AFFiNE’s workspace provider
<WorkspaceProvider store={store}>
{/* AFFiNE UI components */}
</WorkspaceProvider>
Source: [blocksuite/affine/store/src/index.ts](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/affine/store/src/index.ts)
Rendering Rich Text Blocks
The editor host renders rich text components using Blocksuite's standard scope:
import { BlockStdScope } from '@blocksuite/affine/std';
import { RichText } from '@blocksuite/affine/rich-text';
import { css } from 'lit';
const editor = new BlockStdScope();
editor.mount(
<RichText
class={css`padding: 8px;`}
placeholder="Start typing…"
/>,
);
Source: [blocksuite/affine/rich-text/src/rich-text.ts](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/affine/rich-text/src/rich-text.ts)
Implementing a Custom Toolbar
AFFiNE adds interactive toolbars using Blocksuite widget APIs:
import { Toolbar } from '@blocksuite/affine/widgets/toolbar';
import { cssVarV2 } from '@blocksuite/affine/shared/theme';
const myToolbar = new Toolbar();
myToolbar.addButton({
icon: 'bold',
onClick: () => editor.command.exec('formatBold'),
style: `color: ${cssVarV2('icon/primary')}`,
});
// Mount into AFFiNE’s editor container
editor.mount(myToolbar);
Source: [blocksuite/affine/widgets/toolbar/src/toolbar.ts](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/affine/widgets/toolbar/src/toolbar.ts)
Loading Extensions Dynamically
The extension loader enables runtime customization:
import { loadExtension } from '@blocksuite/affine/ext-loader';
import { MyCustomBlock } from './my-custom-block';
loadExtension({
name: '@my-org/custom-block',
components: [MyCustomBlock],
// Optional: define block schema, commands, etc.
});
Source: [blocksuite/affine/ext-loader/src/manager.ts](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/affine/ext-loader/src/manager.ts)
Summary
- BlockSuite is a modular, framework-agnostic library providing collaborative editing building blocks including text, lists, embeds, and databases.
- AFFiNE uses BlockSuite as its core editor engine through the
@blocksuite/affinepackage, which bundles AFFiNE-specific block types and widgets. - The integration relies on
DocCollectionandStorefor data management,BlockStdScopefor UI lifecycle, and widget systems for toolbars and menus. - Real-time collaboration is enabled through Yjs integration in
@blocksuite/affine/store, providing CRDT-based synchronization. - The extension loader system allows AFFiNE to register custom blocks and views at runtime without modifying core BlockSuite code.
Frequently Asked Questions
What is BlockSuite used for?
BlockSuite is a framework-agnostic library designed for building collaborative, real-time editing applications. It provides modular building blocks—including text editors, lists, embeds, databases, and graphics—along with state management and synchronization capabilities powered by Yjs.
How does AFFiNE integrate with BlockSuite?
AFFiNE integrates BlockSuite as its underlying editor engine through the @blocksuite/affine package. This integration includes using DocCollection for workspace management, BlockStdScope for editor lifecycle, and various widget packages for UI components like toolbars and slash menus. The source code in blocksuite/affine/store/src/index.ts and blocksuite/affine/std/src/index.ts demonstrates these core integrations.
Can developers extend BlockSuite with custom blocks?
Yes, developers can extend BlockSuite using the extension loader system defined in blocksuite/affine/ext-loader/src/manager.ts. This system supports dynamic registration of custom block types, view extensions, and commands at runtime, allowing applications like AFFiNE to add specialized functionality without modifying the core BlockSuite library.
Does BlockSuite support real-time collaboration?
Yes, BlockSuite supports real-time collaboration through its integration with Yjs (CRDTs) in the @blocksuite/affine/store package. This enables multiple users to edit documents simultaneously with automatic conflict resolution, transmitting only binary document deltas rather than full state to optimize network usage.
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 →