How to Contribute to the AFFiNE Project: A Complete Developer Guide

Developers can contribute to the AFFiNE project by forking the repository, setting up a local development environment with Node.js and Rust, and submitting pull requests against the canary branch following conventional commit standards.

AFFiNE is an open-source, local-first workspace platform maintained by toeverything that combines note-taking, whiteboarding, and AI assistance. Whether you want to fix bugs, add features, improve documentation, or enhance the UI component library, understanding how to contribute to the AFFiNE project ensures your submissions align with the codebase architecture and community standards.

Setting Up Your Local Development Environment

Before writing code, you must configure the toolchain and build the native dependencies that power AFFiNE's performance-critical features.

Prerequisites and Toolchain Installation

AFFiNE requires Node.js LTS (≈20.x) and Rust installed on your system. Use a version manager like fnm to handle Node versions consistently.

Enable Yarn 4 via Corepack to match the project's package manager:

corepack enable
corepack prepare yarn@stable --activate

Clone your fork and install dependencies:

git clone https://github.com/your-username/AFFiNE.git
cd AFFiNE
yarn install

Building Native Dependencies

AFFiNE uses NAPI-rs for native bindings located in packages/frontend/native/. Build these modules before starting the development server:

yarn affine @affine/native build
yarn affine @affine/server-native build

Launch the local development environment with:

yarn dev

Types of Contributions You Can Make to AFFiNE

The AFFiNE project welcomes diverse contributions beyond code commits. Choose the category that matches your expertise:

  • Bug Reports and Feature Requests – Use the GitHub Issues templates to report problems or propose enhancements with reproducible steps.
  • Code Contributions – Fix bugs, refactor architecture, or implement new features in the frontend, server, or native modules.
  • Documentation – Improve Markdown guides in the docs/ folder, add tutorials, or enhance API references.
  • UI Components – Extend the design system in @affine/component located at packages/frontend/component/src/.
  • Testing – Write unit tests with Vitest or end-to-end tests with Playwright to prevent regressions.
  • Translations – Contribute localization via the external translation platform mentioned in the README.
  • Infrastructure – Optimize CI/CD pipelines in .github/workflows/ or Docker configurations.

Step-by-Step Workflow for Contributing Code

Follow this standardized process to ensure your pull request meets AFFiNE's quality standards:

  1. Fork and Branch – Fork the repository, then create a descriptive branch: git checkout -b fix-database-sync or git checkout -b feature-ai-assistant.
  2. Develop with Conventional Commits – Write clear commit messages following the conventional commit style (e.g., feat: add keyboard shortcut for quick search).
  3. Lint and Format – Run yarn lint to ensure code style consistency before committing.
  4. Test Locally – Execute yarn test for unit tests and verify your changes don't break existing functionality.
  5. Accept the CLA – Edit the CLA file in the repository and submit a pull request to indicate your acceptance of the Contributor License Agreement.
  6. Submit PR – Push your branch to your fork and open a pull request against the canary branch, not master.

Example: Adding a New UI Component

Here is a practical example of contributing a simple button component to the @affine/component package, located at packages/frontend/component/src/.

Create the component file:

// packages/frontend/component/src/ui/HelloButton.tsx
import { useCallback } from 'react';
import { Button } from '@toeverything/components';

export const HelloButton = () => {
  const onClick = useCallback(() => alert('Hello from AFFiNE!'), []);
  return <Button onClick={onClick}>Say Hello</Button>;
};

Export it from the package entry point:

// packages/frontend/component/src/index.ts
export * from './ui/HelloButton';

Add a Storybook story for documentation:

// packages/frontend/component/stories/HelloButton.stories.tsx
import { HelloButton } from '../src/ui/HelloButton';

export default {
  title: 'UI/HelloButton',
  component: HelloButton,
};

export const Default = () => <HelloButton />;

Test your component:

yarn workspace @affine/component test

Key Files and Architecture to Understand

Familiarize yourself with these critical paths to navigate the AFFiNE codebase effectively:

Path Purpose
docs/BUILDING.md Comprehensive setup instructions for the development environment
docs/contributing/tutorial.md Step-by-step onboarding tutorial for new developers
docs/types-of-contributions.md Detailed breakdown of contribution categories
packages/frontend/track/src/tracker.ts Telemetry implementation demonstrating cross-module architecture
packages/frontend/component/src/index.ts Entry point for the UI component library
packages/frontend/native/ NAPI-rs native bindings for performance-critical operations
.github/workflows/ CI/CD pipeline definitions for automated testing and deployment

Testing Your Changes Before Submitting

AFFiNE maintains quality through automated testing. Validate your work using these commands:

Run unit tests across the monorepo:

yarn test

Execute end-to-end tests with Playwright:

yarn workspace @affine-test/affine-local e2e

Always run the full test suite before submitting your pull request to prevent CI failures and ensure your changes integrate cleanly with the canary branch.

Summary

  • Fork the repository and create feature branches against the canary branch, not master.
  • Install Node.js LTS and Rust, then enable Yarn 4 via Corepack before running yarn install.
  • Build native dependencies using yarn affine @affine/native build and yarn affine @affine/server-native build.
  • Contribute across multiple categories: code, documentation, UI components in packages/frontend/component/, tests, translations, and infrastructure.
  • Follow conventional commits, run yarn lint, and execute yarn test before opening pull requests.
  • Accept the CLA by editing the designated file in the repository to complete your first contribution.

Frequently Asked Questions

What programming languages and technologies does AFFiNE use?

AFFiNE is built with TypeScript and React for the frontend, Rust for performance-critical native modules using NAPI-rs, and Node.js for the server components. The project uses Yarn 4 as its package manager and Vitest for unit testing alongside Playwright for end-to-end testing.

Do I need to build native dependencies every time I make changes?

No. You only need to run yarn affine @affine/native build and yarn affine @affine/server-native build when you first clone the repository or when the native Rust code changes. Regular TypeScript or React modifications only require yarn dev to see hot-reload updates.

Which branch should I target when opening a pull request?

Always target the canary branch when contributing to AFFiNE. The master branch represents the stable release, while canary contains the latest development changes. The CI pipelines in .github/workflows/ are configured to validate PRs against this branch.

How do I accept the Contributor License Agreement (CLA)?

To accept the CLA, locate the designated CLA file in the repository root, add your GitHub username to the list of contributors, and submit this change as a pull request. This indicates your legal acceptance of the terms and is required before your substantive contributions can be merged.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →