# Complete Guide to AFFiNE Block Types: Every Built-in Block Explained

> Explore AFFiNE block types and discover over 20 built-in options from paragraphs to databases and whiteboard surfaces. Master AFFiNE's powerful editor today.

- Repository: [Toeverything/AFFiNE](https://github.com/toeverything/AFFiNE)
- Tags: explainer
- Published: 2026-03-05

---

**AFFiNE's editor supports over 20 built-in block types identified by flavour strings prefixed with `affine:`, ranging from basic paragraphs and lists to complex embeds, databases, and whiteboard surfaces.**

AFFiNE block types form the foundation of the editor's content architecture, built on the open-source BlockSuite framework maintained in the [toeverything/AFFiNE](https://github.com/toeverything/AFFiNE) repository. Every piece of content—from simple text to embedded Figma designs—is stored as a typed block with a unique flavour identifier. Understanding these block types is essential for developers extending AFFiNE or automating document creation via the BlockSuite API.

## Understanding AFFiNE's Block Architecture

### The Flavour System

Blocks in AFFiNE are identified by a **flavour string** prefixed with `affine:`. This system allows the editor to distinguish between different content types and apply appropriate rendering, serialization, and interaction logic. The flavour serves as the primary key when creating blocks programmatically via `doc.addBlock(flavour, props, parentId)`.

### Block Hierarchy and Nesting

AFFiNE documents follow a strict hierarchical structure defined in [`blocksuite/affine/shared/src/types/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/shared/src/types/index.ts):

- `affine:page` serves as the root container for every document
- `affine:note` acts as the primary content container within pages
- Content blocks (paragraphs, lists, images) nest inside notes
- Edgeless mode uses `affine:surface` as the canvas root

## Complete Catalogue of AFFiNE Block Types

### Container Blocks

These blocks provide structural organization for documents:

- **`affine:page`** — The top-level page container. Every AFFiNE document starts with this block as its root. Referenced in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 46).

- **`affine:note`** — Generic container for free-form content; the most common parent for text and media blocks. Found in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 49).

### Content Blocks

Fundamental text and media blocks for document creation:

- **`affine:paragraph`** — Rich-text paragraph supporting headings, lists, and inline formatting. Implementation tested in [`tests/blocksuite/e2e/paragraph.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/paragraph.spec.ts) (line 245).

- **`affine:list`** — List block supporting bulleted, numbered, and todo list styles. Created via `doc.addBlock('affine:list', { type: 'bulleted' }, parentId)` as shown in [`tests/blocksuite/e2e/list.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/list.spec.ts) (line 64).

- **`affine:code`** — Code block with syntax highlighting, language selector, and copy functionality. Defined in [`tests/blocksuite/e2e/code/crud.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/code/crud.spec.ts) (line 42).

- **`affine:divider`** — Horizontal rule for visual section separation. Referenced in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 78).

- **`affine:image`** — Inline image supporting local file upload or remote URL. Found in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 88).

- **`affine:bookmark`** — URL bookmark block that fetches preview thumbnails. Located in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 79).

### Embed Blocks

Specialized blocks for embedding external content and linked documents:

- **`affine:embed-github`** — Embedded GitHub gist or file viewer. Referenced in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 89).

- **`affine:embed-figma`** — Figma design embed. Defined in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (line 1005).

- **`affine:embed-youtube`** — YouTube video embed. Configured in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (line 1015).

- **`affine:embed-iframe`** — Generic iframe embed for external web pages. Found in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (line 1050).

- **`affine:embed-linked-doc`** — Inline view of another AFFiNE page (linked document). Defined in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (line 1073).

- **`affine:embed-synced-doc`** — Embedded synced document that stays synchronized with its source. Located in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (line 1115).

### Edgeless and Canvas Blocks

Blocks specific to whiteboard and Edgeless mode:

- **`affine:surface`** — Whiteboard/canvas block used in Edgeless mode. Created in [`tests/blocksuite/e2e/edgeless/edgeless-text.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/edgeless/edgeless-text.spec.ts) (line 616).

- **`affine:surface-ref`** — Reference to a surface used internally for linking Edgeless canvases. Defined in [`blocksuite/affine/blocks/surface/src/view.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/blocks/surface/src/view.ts) (line 22).

### Database Blocks

Structured data blocks:

- **`affine:database`** — Full-featured database table/list block with views. Referenced in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (line 341).

- **`affine:todo`** — Technically a variant of `affine:list` with the "todo" style, representing checklist items. Found in [`tests/blocksuite/e2e/list.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/list.spec.ts) (line 80).

## Programmatic Block Creation with BlockSuite

Developers can instantiate any AFFiNE block type via the BlockSuite API using `doc.addBlock()`. This method accepts the flavour string, properties object, and parent block ID.

### Creating Container Structures

Every AFFiNE document requires a hierarchical structure starting with `affine:page`:

```typescript
// Create the root page container
const pageId = doc.addBlock('affine:page', {}, null);

// Add a note container for content
const noteId = doc.addBlock('affine:note', {}, pageId);

```

*Source:* [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (lines 46, 49)

### Adding Text Content

Insert rich-text paragraphs with initial content:

```typescript
const paragraphId = doc.addBlock(
  'affine:paragraph', 
  { text: 'Hello AFFiNE!' }, 
  noteId
);

```

*Source:* [`tests/blocksuite/e2e/paragraph.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/paragraph.spec.ts) (line 245)

### Inserting Code Blocks

Create syntax-highlighted code blocks with language specification:

```typescript
const codeProps = {
  language: 'typescript',
  // initial empty text will be replaced by the editor UI
};
doc.addBlock('affine:code', codeProps, noteId);

```

*Source:* [`tests/blocksuite/e2e/code/crud.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/code/crud.spec.ts) (line 42)

### Creating Lists

Instantiate various list styles using the type property:

```typescript
// Bulleted list
doc.addBlock('affine:list', { type: 'bulleted' }, noteId);

// Numbered list
doc.addBlock('affine:list', { type: 'numbered' }, noteId);

// Todo/checklist
doc.addBlock('affine:list', { type: 'todo' }, noteId);

```

*Source:* [`tests/blocksuite/e2e/list.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/list.spec.ts) (lines 64, 80)

### Embedding External Content

Insert external resources and linked documents:

```typescript
// GitHub embed
doc.addBlock('affine:embed-github', { url: 'https://gist.github.com/...' }, noteId);

// YouTube video
doc.addBlock('affine:embed-youtube', { url: 'https://youtu.be/...' }, noteId);

// Linked AFFiNE page
doc.addBlock('affine:embed-linked-doc', { pageId: 'some-page-id' }, noteId);

// Synced document (stays updated with source)
doc.addBlock('affine:embed-synced-doc', { pageId: 'source-page-id' }, noteId);

```

*Source:* [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) (lines 1005, 1015, 1073, 1115)

### Adding Whiteboard Surfaces

Create Edgeless mode canvas blocks:

```typescript
// Surface block for whiteboard/Edgeless mode
const surfaceId = doc.addBlock('affine:surface', {}, pageId);

```

*Source:* [`tests/blocksuite/e2e/edgeless/edgeless-text.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/edgeless/edgeless-text.spec.ts) (line 616)

## Key Implementation Files

The block type system is implemented across these critical source files:

- **[`blocksuite/affine/shared/src/types/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/shared/src/types/index.ts)** — Defines the central TypeScript union `BlockFlavour` that enumerates all valid block type strings.

- **[`packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts)** — Controls which block flavours appear in the editor toolbar, including custom surface extensions.

- **`blocksuite/affine/blocks/**`** — Directory housing concrete implementations for each block type, including view components, data models, and service configurations (e.g., [`blocksuite/affine/blocks/paragraph/src/view.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/blocks/paragraph/src/view.ts)).

- **`tests/blocksuite/e2e/**`** — End-to-end test suites demonstrating block instantiation via `doc.addBlock()` for every flavour type.

- **[`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts)** — Defines slash-menu entries and embed configurations for external content blocks (lines 1005-1115).

## Summary

- AFFiNE's editor supports **20+ built-in block types** identified by `affine:`-prefixed flavour strings, built on the BlockSuite framework.
- **Container blocks** (`affine:page`, `affine:note`) provide the hierarchical structure for all documents.
- **Content blocks** include paragraphs, lists (bulleted/numbered/todo), code blocks with syntax highlighting, dividers, images, and bookmarks.
- **Embed blocks** support external integrations including YouTube, Figma, GitHub, generic iframes, and linked/synced AFFiNE documents.
- **Edgeless blocks** (`affine:surface`, `affine:surface-ref`) enable whiteboard and canvas functionality.
- **Database blocks** (`affine:database`) provide structured table and list views, while `affine:todo` represents checklist variants.
- Developers can create blocks programmatically using `doc.addBlock(flavour, props, parentId)` as demonstrated in the BlockSuite test suite.

## Frequently Asked Questions

### What is the difference between `affine:page` and `affine:note` blocks?

The `affine:page` block serves as the root container for every AFFiNE document, representing the top-level page entity in the BlockSuite document model. The `affine:note` block functions as a generic content container that lives inside pages, holding paragraphs, images, and other content blocks. While every document has exactly one page root, it can contain multiple note blocks to create complex document layouts, as shown in [`tests/blocksuite/e2e/zero-width.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/zero-width.spec.ts) (lines 46, 49).

### How do I create a todo list programmatically in AFFiNE?

Todo lists are created using the `affine:list` flavour with the type property set to `'todo'`. Using the BlockSuite API, call `doc.addBlock('affine:list', { type: 'todo' }, parentNoteId)` where `parentNoteId` references the containing note block. This renders as an interactive checklist with toggleable checkboxes, distinct from bulleted or numbered list variants, as demonstrated in [`tests/blocksuite/e2e/list.spec.ts`](https://github.com/toeverything/AFFiNE/blob/main/tests/blocksuite/e2e/list.spec.ts) (line 80).

### What is the difference between `embed-linked-doc` and `embed-synced-doc`?

The `affine:embed-linked-doc` block creates a static inline view of another AFFiNE page at the time of insertion, functioning as a snapshot reference to the linked content. The `affine:embed-synced-doc` block maintains a live synchronization with the source document, automatically updating the embedded content whenever the original page changes. Both are configured in [`blocksuite/affine/widgets/keyboard-toolbar/src/config.ts`](https://github.com/toeverything/AFFiNE/blob/main/blocksuite/affine/widgets/keyboard-toolbar/src/config.ts) at lines 1073 and 1115 respectively.

### Can I create custom block types in AFFiNE?

Yes, AFFiNE supports custom block flavours that extend the core `affine:` namespace or use custom prefixes like `custom:affine:surface:bookmark`. These are registered through the BlockSuite schema system and can be added to the toolbar via [`packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/src/blocksuite/view-extensions/editor-config/toolbar/index.ts). Custom blocks require implementing the corresponding view, model, and service classes following the BlockSuite block definition pattern established in the `blocksuite/affine/blocks/` directory structure.