Best Open Source Alternatives to Notion 2026
TL;DR
Notion charges $10/user/month. The best open source alternatives: AppFlowy (AGPL 3.0, ~60K GitHub stars, Rust/Flutter) for a full Notion-like experience with databases, kanban, and docs; AFFiNE (MIT, ~45K stars, TypeScript) for a whiteboard+doc hybrid; and Outline (BSL, ~28K stars, TypeScript/React) for team wikis. All self-host via Docker and store your data on your server.
Key Takeaways
- AppFlowy: AGPL 3.0, ~60K stars — Rust backend + Flutter frontend, databases, kanban, docs, grids
- AFFiNE: MIT, ~45K stars — doc + whiteboard + database in one, local-first with optional sync server
- Outline: BSL, ~28K stars — focused team wiki/knowledge base, excellent Slack/Notion import
- SiYuan: AGPL 3.0, ~30K stars — local-first block editor, full offline, strong search
- Logseq: AGPL 3.0, ~33K stars — outliner/graph notes, plain Markdown files, no database backend
- Pick by use case: Team wiki → Outline; Full Notion replacement → AppFlowy; Whiteboard hybrid → AFFiNE
Comparison Table
| Feature | AppFlowy | AFFiNE | Outline | SiYuan |
|---|---|---|---|---|
| License | AGPL 3.0 | MIT | BSL 1.1 | AGPL 3.0 |
| GitHub Stars | ~60K | ~45K | ~28K | ~30K |
| Backend | Rust | Node.js | Node.js | Go |
| Frontend | Flutter | TypeScript | React | TypeScript |
| Databases/grids | Yes | Yes | No | Yes |
| Kanban boards | Yes | Yes | No | Yes |
| Whiteboard | No | Yes | No | No |
| Team wiki | Yes | Yes | Yes | No |
| Notion import | Yes | Yes | Yes | No |
| Local-first option | Yes | Yes | No | Yes |
| Self-host Docker | Yes | Yes | Yes | Yes |
| Mobile apps | Yes | Yes | Limited | Yes |
| Real-time collab | Yes | Yes | Yes | No |
Option 1: AppFlowy
AppFlowy is the closest 1:1 Notion replacement. Databases with multiple views (grid, board, calendar, gallery), rich text docs, nested pages — all in a Flutter desktop/mobile app or web.
# docker-compose.yml
services:
appflowy_cloud:
image: appflowyinc/appflowy_cloud:latest
container_name: appflowy_cloud
restart: unless-stopped
ports:
- "8000:8000"
environment:
RUST_LOG: info
APPFLOWY_DATABASE_URL: "postgres://appflowy:${POSTGRES_PASSWORD}@postgres:5432/appflowy"
APPFLOWY_REDIS_URI: "redis://redis:6379"
APPFLOWY_GOTRUE_JWT_SECRET: "${JWT_SECRET}"
APPFLOWY_GOTRUE_JWT_EXP: 7200
APPFLOWY_GOTRUE_BASE_URL: "http://gotrue:9999"
APPFLOWY_GOTRUE_EXT_URL: "https://appflowy.yourdomain.com"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
gotrue:
image: appflowyinc/gotrue:latest
container_name: appflowy_gotrue
restart: unless-stopped
environment:
GOTRUE_SITE_URL: "https://appflowy.yourdomain.com"
GOTRUE_JWT_SECRET: "${JWT_SECRET}"
GOTRUE_DB_DRIVER: "postgres"
DATABASE_URL: "postgres://supabase_auth_admin:${POSTGRES_PASSWORD}@postgres:5432/supabase_auth"
GOTRUE_SMTP_HOST: "smtp.yourdomain.com"
GOTRUE_SMTP_PORT: 587
GOTRUE_SMTP_USER: "${SMTP_USER}"
GOTRUE_SMTP_PASS: "${SMTP_PASS}"
GOTRUE_MAILER_AUTOCONFIRM: "false"
API_EXTERNAL_URL: "https://appflowy.yourdomain.com"
depends_on:
- postgres
postgres:
image: pgvector/pgvector:pg16
container_name: appflowy_postgres
restart: unless-stopped
environment:
POSTGRES_USER: appflowy
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: appflowy
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appflowy"]
interval: 10s
start_period: 20s
redis:
image: redis:7-alpine
container_name: appflowy_redis
restart: unless-stopped
volumes:
- redis_data:/data
minio:
image: minio/minio:latest
container_name: appflowy_minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: "${MINIO_USER}"
MINIO_ROOT_PASSWORD: "${MINIO_PASSWORD}"
volumes:
- minio_data:/data
volumes:
postgres_data:
redis_data:
minio_data:
# .env
POSTGRES_PASSWORD=your-secure-db-password
JWT_SECRET=your-32-char-secret
SMTP_USER=you@yourdomain.com
SMTP_PASS=smtp-password
MINIO_USER=appflowy
MINIO_PASSWORD=your-minio-password
docker compose up -d
AppFlowy Caddy Config
appflowy.yourdomain.com {
reverse_proxy localhost:8000
}
Connect AppFlowy Desktop
- Download AppFlowy Desktop
- Click Sign In → Self-hosted server
- Enter:
https://appflowy.yourdomain.com - Create account / sign in
AppFlowy Database Views
AppFlowy databases support multiple views of the same data:
- Grid: Spreadsheet-style with filtered/sorted rows
- Board: Kanban grouped by any property
- Calendar: Date-based view
- Gallery: Card layout for visual content
Database: Project Tasks
├── Grid view: All tasks with status, priority, assignee
├── Board view: Kanban grouped by "Status" (Todo/In Progress/Done)
└── Calendar view: Grouped by "Due Date"
Option 2: AFFiNE
AFFiNE combines a block-based doc editor with an infinite whiteboard — useful for design thinking, architecture diagrams, and visual note-taking alongside written docs.
# docker-compose.yml
services:
affine:
image: ghcr.io/toeverything/affine-graphql:stable
container_name: affine
restart: unless-stopped
ports:
- "3010:3010"
volumes:
- affine_config:/root/.affine/config
- affine_storage:/root/.affine/storage
environment:
NODE_OPTIONS: "--import=./scripts/register.js"
AFFINE_CONFIG_PATH: "/root/.affine/config"
REDIS_SERVER_HOST: redis
DATABASE_URL: "postgresql://affine:${POSTGRES_PASSWORD}@postgres:5432/affine"
NEXTAUTH_URL: "https://affine.yourdomain.com"
AFFINE_SERVER_HTTPS: "true"
AFFINE_SERVER_HOST: "affine.yourdomain.com"
AFFINE_SERVER_PORT: "3010"
AFFINE_ADMIN_EMAIL: "${ADMIN_EMAIL}"
AFFINE_ADMIN_PASSWORD: "${ADMIN_PASSWORD}"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis:7-alpine
container_name: affine_redis
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: affine_postgres
restart: unless-stopped
environment:
POSTGRES_USER: affine
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: affine
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U affine"]
interval: 10s
start_period: 30s
volumes:
affine_config:
affine_storage:
postgres_data:
affine.yourdomain.com {
reverse_proxy localhost:3010
}
AFFiNE Local-First Mode
AFFiNE also works entirely offline — no server needed:
- Download AFFiNE Desktop
- Data stored in
~/.affine/as SQLite - Self-host only needed for team sync
Option 3: Outline (Team Wiki)
Outline is purpose-built for team knowledge bases — clean editor, nested collections, Slack integration, full-text search. Less of a database tool, more of a clean wiki.
# docker-compose.yml
services:
outline:
image: outlinewiki/outline:latest
container_name: outline
restart: unless-stopped
ports:
- "3000:3000"
environment:
SECRET_KEY: "${SECRET_KEY}"
UTILS_SECRET: "${UTILS_SECRET}"
DATABASE_URL: "postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline"
REDIS_URL: "redis://redis:6379"
URL: "https://wiki.yourdomain.com"
PORT: 3000
# Auth (choose one):
OIDC_CLIENT_ID: "${OIDC_CLIENT_ID}"
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
OIDC_AUTH_URI: "${OIDC_AUTH_URI}"
OIDC_TOKEN_URI: "${OIDC_TOKEN_URI}"
OIDC_USERINFO_URI: "${OIDC_USERINFO_URI}"
# Or Google auth:
# GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID}"
# GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET}"
# Storage (S3 or local):
FILE_STORAGE: "local"
FILE_STORAGE_LOCAL_ROOT_DIR: "/var/lib/outline/data"
# Email:
SMTP_HOST: "smtp.yourdomain.com"
SMTP_PORT: 587
SMTP_USERNAME: "${SMTP_USER}"
SMTP_PASSWORD: "${SMTP_PASS}"
SMTP_FROM_EMAIL: "outline@yourdomain.com"
volumes:
- outline_data:/var/lib/outline/data
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: outline
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: outline
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U outline"]
interval: 10s
start_period: 20s
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
outline_data:
postgres_data:
wiki.yourdomain.com {
reverse_proxy localhost:3000
}
Outline Auth: Using Authentik (OIDC)
If you're running Authentik for SSO:
- Authentik Admin → Applications → Providers → Create → OAuth2/OpenID Provider
- Name:
Outline, Redirect URI:https://wiki.yourdomain.com/auth/oidc.callback - Copy Client ID, Secret, and OIDC endpoints into Outline env vars
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret
OIDC_AUTH_URI=https://auth.yourdomain.com/application/o/outline/authorize/
OIDC_TOKEN_URI=https://auth.yourdomain.com/application/o/outline/token/
OIDC_USERINFO_URI=https://auth.yourdomain.com/application/o/outline/userinfo/
OIDC_DISPLAY_NAME="Your SSO"
Import from Notion
Outline has a Notion importer:
- In Notion: Settings → Export → Markdown & CSV (export all workspace)
- In Outline: Settings → Import → Notion → upload the ZIP
Option 4: SiYuan (Local-First, Offline)
For individuals who want everything local with optional sync:
services:
siyuan:
image: b3log/siyuan:latest
container_name: siyuan
restart: unless-stopped
ports:
- "6806:6806"
volumes:
- siyuan_workspace:/siyuan/workspace
environment:
TZ: America/Los_Angeles
command: ["--workspace=/siyuan/workspace", "--accessAuthCode=${ACCESS_CODE}"]
volumes:
siyuan_workspace:
Visit http://your-server:6806 with your access code.
Importing from Notion
All four tools import Notion exports:
# 1. Export from Notion:
# Settings → Export → Markdown & CSV → Export All
# 2. For AppFlowy:
# Settings → Import → Notion → upload .zip
# 3. For AFFiNE:
# New workspace → Import → Notion
# 4. For Outline:
# Settings → Import → Notion
Decision Guide
Choose AppFlowy if:
- You need a full Notion replacement (databases + docs + kanban + calendar views)
- Your team is 1-50 people
- You want a native desktop app (Flutter-based, fast)
Choose AFFiNE if:
- You need a whiteboard + doc hybrid
- You like local-first with optional sync
- Design thinking and visual collaboration matter
Choose Outline if:
- Primary use case is team knowledge base / wiki
- You want the cleanest writing experience
- Slack integration is important
Choose SiYuan if:
- You want everything stored locally (single user or small team)
- Offline-first is mandatory
- You don't want a cloud sync component at all
Maintenance
# Update AppFlowy:
docker compose pull
docker compose up -d
# Backup AppFlowy PostgreSQL:
docker exec appflowy_postgres pg_dump -U appflowy appflowy \
| gzip > appflowy-backup-$(date +%Y%m%d).sql.gz
# Backup AFFiNE:
docker exec affine_postgres pg_dump -U affine affine \
| gzip > affine-backup-$(date +%Y%m%d).sql.gz
tar -czf affine-storage-$(date +%Y%m%d).tar.gz \
$(docker volume inspect affine_affine_storage --format '{{.Mountpoint}}')
# Backup Outline:
docker exec outline-postgres-1 pg_dump -U outline outline \
| gzip > outline-backup-$(date +%Y%m%d).sql.gz
See all open source productivity and collaboration tools at OSSAlt.com/categories/productivity.