6 min read

AFFiNE: Docs and Whiteboards in One Workspace (GitHub, Scanned)

A local-first Notion and Miro alternative where docs, whiteboards and databases share one canvas.

AFFiNE logo
✅
Scan: safe. Nothing malicious. Two things to know: the apps send usage analytics and Sentry error reports by default until you turn telemetry off in settings, and the self-hosted server carries one critical advisory, in the piscina worker pool, awaiting an update. Scanned Sep 29, 2026; the full report is below.

AFFiNE is a knowledge workspace that merges a document editor with an endless whiteboard. Any page can switch between a writing view and an edgeless canvas, where rich text, sticky notes, embedded web pages, multi-view databases, shapes and slides sit side by side. That makes it a single place for notes, wikis, planning boards and presentations, the job that otherwise takes Notion plus Miro.

It earns its place by being local-first. Your workspace lives on your disk and works offline, with real-time sync and collaboration added on top through AFFiNE Cloud or your own server, built on the Yjs CRDT and the team's own BlockSuite editor and OctoBase database. AFFiNE AI can draft, summarize, turn outlines into slides or mind maps and generate prototypes on the canvas.

AFFiNE is made by Toeverything, a Singapore company, and has about 73,000 stars. The licensing is split: the client and most of the code are MIT, while the server code in packages/backend carries a separate licence under which the Community Edition parts are MPL-2.0 and enterprise features need a subscription. Self-hosting the Community Edition is free.

Who it is for

Notion users who want their notes on their own disk, visual thinkers who plan on whiteboards, and small teams that want one self-hostable tool for docs and diagrams.

Getting started

1. Desktop app on macOS with Homebrew (Windows and Linux builds are on the releases page)

brew install --cask affine

2. Self-host: download the Compose file from the latest release

mkdir affine && cd affine && wget -O docker-compose.yml https://github.com/toeverything/affine/releases/latest/download/docker-compose.yml

3. Start the server with its Postgres and Redis, then open it on port 3010

docker compose up -d && open http://localhost:3010

The self-hosting guide at docs.affine.pro covers storage paths, configuration and upgrades. AI features need a model provider: on AFFiNE Cloud they are a paid plan, and on a self-hosted server you configure your own provider key. The apps send usage analytics and Sentry error reports by default; turn telemetry off in the app's settings if you prefer.

Safety scan

We cloned toeverything/AFFiNE at commit b71bb7c on Sep 29, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • One secret hit: packages/backend/native/src/entitlement.rs line 378, a P-256 private key named TEST_PRIVATE_KEY inside the file's #[cfg(test)] module, used to sign test licence payloads. It is compiled only into tests and is not a production key. The repository is large: about 1.24 million lines in 10,273 files.
  • The 13 pattern hits are long lines: base64 images in AI end-to-end test specs, inline SVG icons and tooltip illustrations, and a test fixture; none decodes and runs code. The binaries are six Yjs document snapshots used as test fixtures and the Android Gradle wrapper. The npm hooks (workspace init, Husky, prisma generate, a template build) run for developers, not users.
  • Telemetry: enableTelemetry defaults to true in packages/common/infra. When it is on, the client opts into the usage tracker and enables Sentry; turning it off in settings opts out of both.
  • 57 known advisories, 1 critical (22 high). The critical one is piscina 5.2.0, a dependency of the self-hosted server: a prototype-pollution gadget that needs a separate prototype-pollution bug to become code execution. The desktop app's Electron 39.8.10 has four high sandbox-related advisories, the server's nodemailer and @fastify/busboy have several more, and the Rust side has quick-xml denial-of-service issues.
  • 11 workflows. One uses pull_request_target, auto-labeler, which checks out the base branch and runs actions/labeler; none of the 33 third-party actions is pinned to a commit. Security policy, Renovate, CodeQL and licence present; the contributing guide lives in docs/ rather than the root.

What the scanner counted

CheckResult
Secrets1 candidate found and read; see the notes above.
Suspicious code13 pattern hits found and read; every one is listed under the raw findings.
Install-time code3 npm lifecycle scripts. 5 Cargo build scripts. 3 installer scripts
Committed binaries7 executable or compiled objects committed; listed under the raw findings.
CI workflows11 workflows. 1 uses pull_request_target, none check out the pull request head. 33 of 33 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often github.com, affine.pro, app.affine.pro, cdn.affine.pro. No URLs to bare IP addresses.
Known vulnerabilities57 advisories across 4,195 pinned packages: 1 critical, 22 high, 13 moderate, 4 low, 17 unrated. Cargo.lock: 1,100 packages, 25 advisories; yarn.lock: 3,095 packages, 32 advisories.
Project hygieneHas security policy, automated dependency updates, CodeQL, licence file. Missing contributing guide.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (1, redacted)
WhereRuleMatch
packages/backend/native/src/entitlement.rs:378private-key-----B…--- (27 chars)
Pattern hits (13)
WhereRuleMatch
blocksuite/affine/blocks/embed/src/embed-figma-block/configs/tooltips.ts:20very-long-line5972 chars
blocksuite/affine/blocks/embed/src/embed-html-block/configs/tooltips.ts:30very-long-line6235 chars
blocksuite/affine/components/src/icons/ai.ts:33very-long-line7704 chars
packages/backend/server/src/__tests__/utils/copilot.ts:701very-long-line5872 chars
packages/frontend/core/src/desktop/dialogs/setting/general-setting/plans/lifetime/assets.ts:20very-long-line3465 chars
packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/assets.ts:5very-long-line5206 chars
packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/journal/assets.ts:70very-long-line5176 chars
tests/affine-cloud-copilot/e2e/ai-action/explain-image.spec.ts:6very-long-line9725 chars
tests/affine-cloud-copilot/e2e/ai-action/generate-an-image-with-image.spec.ts:6very-long-line9725 chars
tests/affine-cloud-copilot/e2e/ai-action/generate-image-caption.spec.ts:6very-long-line9725 chars
tests/affine-cloud-copilot/e2e/ai-action/image-filter.spec.ts:6very-long-line9725 chars
tests/affine-cloud-copilot/e2e/ai-action/image-processing.spec.ts:6very-long-line9725 chars
tests/affine-cloud-copilot/e2e/chat-with/image-block.spec.ts:6very-long-line9725 chars
npm lifecycle scripts (3)
  • package.json postinstall: yarn affine init && yarn husky
  • packages/backend/server/package.json postinstall: prisma generate
  • packages/frontend/templates/package.json postinstall: yarn build
Installer scripts (3)
Committed binaries (7)
  • packages/common/reader/__tests__/__fixtures__/test-doc-with-ai-editable.snapshot.bin: .bin, 62 KB
  • packages/frontend/apps/android/App/gradle/wrapper/gradle-wrapper.jar: JAR, 44 KB
  • packages/backend/server/src/__tests__/__fixtures__/test-doc.snapshot.bin: .bin, 36 KB
  • packages/common/reader/__tests__/__fixtures__/test-doc.snapshot.bin: .bin, 36 KB
  • packages/backend/server/src/__tests__/__fixtures__/test-doc-with-blob.snapshot.bin: .bin, 2 KB
  • packages/backend/server/src/__tests__/__fixtures__/test-root-doc.snapshot.bin: .bin, 1 KB
  • packages/common/reader/__tests__/__fixtures__/test-root-doc.snapshot.bin: .bin, 1 KB
Worst known vulnerabilities (24 of 57)
AdvisorySeverityPackageSummary
GHSA-67c8-pqhq-4rmxcriticalpiscina@5.2.0piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env
RUSTSEC-2026-0194highquick-xml@0.37.5Quadratic run time when checking a start tag for duplicate attribute names
RUSTSEC-2026-0195highquick-xml@0.37.5Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
RUSTSEC-2026-0194highquick-xml@0.38.4Quadratic run time when checking a start tag for duplicate attribute names
RUSTSEC-2026-0195highquick-xml@0.38.4Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
RUSTSEC-2026-0194highquick-xml@0.40.1Quadratic run time when checking a start tag for duplicate attribute names
RUSTSEC-2026-0195highquick-xml@0.40.1Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
GHSA-x8mw-p69m-v3mxhigh@fastify/busboy@3.1.1@fastify/busboy vulnerable to Denial of Service via prototype-named multipart part header
GHSA-xjh9-v7x6-24jwhigh@fastify/busboy@3.1.1@fastify/busboy vulnerable to Denial of Service via oversized multipart boundary
GHSA-m9gg-hp2v-232jhigh@grpc/grpc-js@1.14.4@grpc/grpc-js: In certain configurations, getAuthContext can return unauthorized certificates as though they were author…
GHSA-vfj7-8cjw-p6xmhighbraces@3.0.3braces vulnerable to stack-exhaustion denial of service through deeply nested patterns
GHSA-9qh4-3jw8-366whighelectron@39.8.10Electron: <webview> can enable Node.js integration in Web Workers despite embedder restrictions
GHSA-gr2m-v5gq-v685highelectron@39.8.10Electron: Windows opened from a sandboxed top-level document do not inherit its sandbox restrictions
GHSA-hq2x-r82h-9wj4highelectron@39.8.10Electron drops inherited HTML sandbox restrictions for popups opened through OpenURLFromTab
GHSA-j84w-jfhq-vhvjhighelectron@39.8.10Electron: File and HTTP protocol handlers allow cross-origin reads without corsEnabled
GHSA-2gc4-cqfq-p2gvhighengine.io@6.6.9Socket.IO: Engine.IO Protocol Revision Mismatch DoS
GHSA-7pqw-9j4j-h8q3highextract-zip@2.0.1extract-zip allows arbitrary file writes through symlink archive entries
GHSA-jmr9-qjv8-65gvhighextract-zip@2.0.1extract-zip unvalidated symlink path traversal
GHSA-ch52-4w7c-c8xphighhttp-cache-semantics@4.2.0http-cache-semantics max-stale handling can disclose cross-user cached responses
GHSA-w3rx-r6r6-pgprhighimage-size@0.7.5image-size: ICNS parser allows denial of service through an infinite loop
GHSA-prgh-xp8r-p3m5highnodemailer@9.1.1Nodemailer addressparser: O(n^2) on comment-joined addresses enables a remote DoS (reachable via mailparser)
GHSA-v53p-9fqp-m79jhighnodemailer@9.1.1Nodemailer: Quadratic backtracking in the addressparser free-text fallback allows remote denial of service
GHSA-rfgv-xxqx-mfg5highundici@6.28.0undici vulnerable to Denial of Service via unrequested WebSocket subprotocol
GHSA-4grx-2x9w-596cmoderatersa@0.9.10Marvin Attack: potential key recovery through timing sidechannels
Workflows worth a look

By the numbers

Stars73.2K
Forks5,327
Contributors269
Commits11.5K
Open issues649
Open pull requests115
Releases587
Latest releasev0.27.4
Licencecustom
Main languageTypeScript
Project age4 years
Last pushSep 30, 2026
Tracked files10,273
Lines of code1.2M
Checkout size124 MB

Lines by language: TypeScript 860.1K, JSON 188.4K, Rust 101.5K, Swift 42.4K, Markdown 17.1K, Kotlin 9,227.

Questions

Is AFFiNE free?

The desktop app and the self-hosted Community Edition are free. The client code is MIT; the server code has its own licence, with Community Edition parts under MPL-2.0 and an Enterprise Edition, adding features such as SSO and audit, sold by subscription. AFFiNE Cloud has a free tier and paid plans, and AFFiNE AI on the cloud is a paid add-on.

Does AFFiNE work offline?

Yes. It is local-first: workspaces are stored on your device and work without a connection. Sync and real-time collaboration happen when you connect a workspace to AFFiNE Cloud or to your own self-hosted server.

Can AFFiNE import from Notion?

AFFiNE can import Markdown and HTML, which is how Notion exports a workspace, along with other formats; the import options are in the app's import dialog. Complex Notion databases may need tidying after the move.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.