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/componentlocated atpackages/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:
- Fork and Branch – Fork the repository, then create a descriptive branch:
git checkout -b fix-database-syncorgit checkout -b feature-ai-assistant. - Develop with Conventional Commits – Write clear commit messages following the conventional commit style (e.g.,
feat: add keyboard shortcut for quick search). - Lint and Format – Run
yarn lintto ensure code style consistency before committing. - Test Locally – Execute
yarn testfor unit tests and verify your changes don't break existing functionality. - Accept the CLA – Edit the CLA file in the repository and submit a pull request to indicate your acceptance of the Contributor License Agreement.
- Submit PR – Push your branch to your fork and open a pull request against the
canarybranch, notmaster.
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
canarybranch, notmaster. - Install Node.js LTS and Rust, then enable Yarn 4 via Corepack before running
yarn install. - Build native dependencies using
yarn affine @affine/native buildandyarn 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 executeyarn testbefore 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →