ZhFahim/anchor

Offline first, self hostable note taking application

TypeScript

1,375

185 commits

updated Oct 9, 2026

See the code

README

Anchor

Anchor

An offline first, self hostable note taking application

Version License: AGPL v3 Docker Discord

ZhFahim%2Fanchor | Trendshift

Anchor focuses on speed, privacy, simplicity, and reliability across mobile and web. Notes are stored locally, editable offline, and synced across devices when online.

Features

  • Rich Text Editor - Create and edit notes with powerful formatting (bold, italic, underline, headings, lists, checkboxes)
  • Offline First - All edits work offline with local database
  • Note Sharing - Share notes with other users (viewer or editor)
  • Note History - Read earlier versions of a note and put one back
  • Tags System - Organize notes with custom tags and colors
  • Attachments - Attach images and audio to notes
  • Note Backgrounds - Customize notes with solid colors and patterns
  • Pin Notes - Pin important notes for quick access
  • Archive Notes - Archive notes for later reference
  • Reminders - Set a time on any note and get a notification on your phone, once or repeating
  • Search - Search notes locally by title or content
  • Trash - Soft delete notes with recovery period
  • Automatic Sync - Sync changes across devices when online
  • Import & Export - Back up your full library, or move notes in and out as plain Markdown
  • Home Screen Widget - Quick access to your notes from the Android home screen
  • Admin Panel - User management, registration control, and system statistics
  • OIDC Authentication - Sign in with OpenID Connect providers (Pocket ID, Authelia, Keycloak, etc.)

Screenshots

Web App

Web Light Mode Web Dark Mode

Mobile App

Mobile Light Mode Mobile Dark Mode

Self Hosting With Docker

  1. Create a docker-compose.yml file:

    services:
      anchor:
        image: ghcr.io/zhfahim/anchor:latest
        container_name: anchor
        restart: unless-stopped
        ports:
          - "3000:3000"
        volumes:
          - anchor_data:/data
    
    volumes:
      anchor_data:
    
  2. (Optional) Configure environment: Add environment variables to the environment section. Most users can skip this step - defaults work out of the box.

    Available options:

    VariableRequiredDefaultDescription
    APP_URLNohttp://localhost:3000Base URL where Anchor is served
    JWT_SECRETNo(auto-generated)Auth token secret. Min 16 characters when set
    DATA_DIRNo/dataRoot directory for persisted uploads
    CORS_ORIGINSNo(allow all)Comma-separated allowlist of CORS origins
    PG_HOSTNo(empty)External Postgres host (leave empty for embedded)
    PG_PORTNo5432Postgres port
    PG_USERNoanchorPostgres username
    PG_PASSWORDNopasswordPostgres password
    PG_DATABASENoanchorDatabase name
    USER_SIGNUPNo(not set)Sign up mode: disabled, enabled, or review. If not set, admins can control it via the admin panel
    OIDC_ENABLEDNo—Enable OIDC authentication
    OIDC_PROVIDER_NAMENo"OIDC Provider"Display name for the login button
    OIDC_ISSUER_URLWhen OIDC enabled—Base URL of your OIDC provider
    OIDC_CLIENT_IDWhen OIDC enabled—OIDC client ID
    OIDC_CLIENT_SECRETNo—OIDC client secret. Omit for public client (PKCE)
    DISABLE_INTERNAL_AUTHNofalseHide local login form when OIDC is enabled (OIDC-only mode)
  3. Start the container:

    docker compose up -d
    
  4. Access the app: Open http://localhost:3000

Pre-release (Beta) Image

To test upcoming features before they are officially released, use the next tag:

services:
  anchor:
    image: ghcr.io/zhfahim/anchor:next
    container_name: anchor
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - anchor_data:/data

volumes:
  anchor_data:

Warning: The next image is built from the next branch and may contain incomplete features or breaking changes. Do not use it in production. Back up your data before switching.

Option 2: Building from Source

If you want to build from source or customize the image:

  1. Clone the project:

    git clone https://github.com/zhfahim/anchor.git
    cd anchor
    
  2. Start the container:

    docker compose up -d
    

    The docker-compose.yml file will build the image from source automatically.

Mobile App

Download the Android mobile app.

  1. Visit the releases page: Go to GitHub Releases.

  2. Download the latest release: Multiple APK files are available:

    • Universal APK (anchor-{version}.apk) - Recommended for most users, works on all devices
    • Architecture-specific APKs - Smaller file sizes for specific CPU architectures

OIDC Authentication

Anchor supports OpenID Connect (OIDC) authentication for simplified credential management and streamlined multi-user deployments.

Features

  • Support for standard OIDC providers (Pocket ID, Authelia, Authentik, Keycloak, etc.)
  • Configuration via environment variables or admin settings UI
  • OIDC only mode: disable local username/password login
  • Support for public OIDC clients (PKCE, no client secret required)
  • Auto create users on first login (if user signup is not disabled)
  • Auto link existing users by email

Configuration

Mobile app and Public client

If you want to use OIDC in the mobile app, configure Anchor as a Public client (PKCE, no client secret) in your OIDC provider. Add this redirect URI in your OIDC provider:

anchor://oidc/callback

Required Callback URL (Web)

When configuring your OIDC provider for web login, add this callback/redirect URL:

{APP_URL}/api/auth/oidc/callback

For example, if your Anchor instance is at https://notes.example.com, the callback URL would be:

https://notes.example.com/api/auth/oidc/callback

Environment Variables

Configure OIDC via environment variables in your docker-compose.yml. Pocket ID example:

services:
  anchor:
    image: ghcr.io/zhfahim/anchor:latest
    environment:
      - OIDC_ENABLED=true
      - OIDC_PROVIDER_NAME=Pocket ID
      - OIDC_ISSUER_URL=https://pocketid.example.com
      - OIDC_CLIENT_ID=your-client-id
      - OIDC_CLIENT_SECRET=your-client-secret # Optional for public clients
      - DISABLE_INTERNAL_AUTH=false
      - APP_URL=https://notes.example.com

Admin UI Configuration

Alternatively, configure OIDC via the admin panel (Settings → OIDC Authentication) when the three env vars are not all set.

Backup and Restore

Log into your Anchor deployment, go to Settings, scroll to Export & Import and export Anchor backup (.zip).

The resulting anchor-export-YYYY-MM-DD.zip contains:

  • manifest.json which includes the backup metadata, tags, notes, and attachment references in plain text
  • the referenced attachments, stored within the attachments folder structure

Restore the notes by uploading that file through the web UI. Go to Settings, then scroll down to the Export & Import section.

Troubleshooting & Collecting Logs

Anchor never collects any data. When you need to report a bug, you can collect logs yourself and share them with the maintainer.

Mobile app

  1. Reproduce the issue.
  2. Open Settings → View Logs.
  3. Tap the Export button at the bottom, then share the saved .log file in your bug report.

Sensitive values are stripped before anything is written to the log file. This includes authorization headers, passwords, tokens, refresh tokens, secrets, and email addresses, which are always replaced with ***.

Logs are stored locally on the device only (rolling, ~2 MB max).

Roadmap

Future planned features:

  • Real-time collaboration

Tech Stack

  • Backend: Nest.js, PostgreSQL, Prisma
  • Mobile: Flutter
  • Web: Next.js, TypeScript

Contributing

  1. Fork the repository
  2. Create a feature branch:
    git checkout -b feature/your-feature
    
  3. Make your changes
  4. Ensure builds pass and code is linted:
    • Web: cd web && pnpm build && pnpm check
    • Server: cd server && pnpm build && pnpm check
  5. Commit changes:
    git commit -m "Describe your change"
    
  6. Push and create a Pull Request

Code style

Linting and formatting are enforced in CI and by a pre-commit hook (.githooks/pre-commit) that checks staged files. Running pnpm install in either web or server enables the hook automatically (via the prepare script). To enable it manually:

git config core.hooksPath .githooks

Before committing, fix issues with pnpm check:fix in the relevant project.

Design tokens

The web app's colors, text sizes, spacing, corners, shadows and motion live in design/tokens/ (W3C Design Tokens format). web/app/styles/tokens.css, web/app/styles/notes.css and web/lib/design/tokens.ts are built from them, so change the tokens rather than those files. After changing a token, run this from the repository root (it reads icons from web/node_modules, so run pnpm install in web first):

node design/build/build.mjs

CI runs it with --check and fails if the built files are out of date.

Support

If you find Anchor useful, consider supporting its development:

Buy me a coffee

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL v3) - see the LICENSE file for details.

ZhFahim/anchor

Offline first, self hostable note taking application

TypeScript

1,375

185 commits

updated Oct 9, 2026

See the code

README

Anchor

Anchor

An offline first, self hostable note taking application

Version License: AGPL v3 Docker Discord

ZhFahim%2Fanchor | Trendshift

Anchor focuses on speed, privacy, simplicity, and reliability across mobile and web. Notes are stored locally, editable offline, and synced across devices when online.

Features

  • Rich Text Editor - Create and edit notes with powerful formatting (bold, italic, underline, headings, lists, checkboxes)
  • Offline First - All edits work offline with local database
  • Note Sharing - Share notes with other users (viewer or editor)
  • Note History - Read earlier versions of a note and put one back
  • Tags System - Organize notes with custom tags and colors
  • Attachments - Attach images and audio to notes
  • Note Backgrounds - Customize notes with solid colors and patterns
  • Pin Notes - Pin important notes for quick access
  • Archive Notes - Archive notes for later reference
  • Reminders - Set a time on any note and get a notification on your phone, once or repeating
  • Search - Search notes locally by title or content
  • Trash - Soft delete notes with recovery period
  • Automatic Sync - Sync changes across devices when online
  • Import & Export - Back up your full library, or move notes in and out as plain Markdown
  • Home Screen Widget - Quick access to your notes from the Android home screen
  • Admin Panel - User management, registration control, and system statistics
  • OIDC Authentication - Sign in with OpenID Connect providers (Pocket ID, Authelia, Keycloak, etc.)

Screenshots

Web App

Web Light Mode Web Dark Mode

Mobile App

Mobile Light Mode Mobile Dark Mode

Self Hosting With Docker

  1. Create a docker-compose.yml file:

    services:
      anchor:
        image: ghcr.io/zhfahim/anchor:latest
        container_name: anchor
        restart: unless-stopped
        ports:
          - "3000:3000"
        volumes:
          - anchor_data:/data
    
    volumes:
      anchor_data:
    
  2. (Optional) Configure environment: Add environment variables to the environment section. Most users can skip this step - defaults work out of the box.

    Available options:

    VariableRequiredDefaultDescription
    APP_URLNohttp://localhost:3000Base URL where Anchor is served
    JWT_SECRETNo(auto-generated)Auth token secret. Min 16 characters when set
    DATA_DIRNo/dataRoot directory for persisted uploads
    CORS_ORIGINSNo(allow all)Comma-separated allowlist of CORS origins
    PG_HOSTNo(empty)External Postgres host (leave empty for embedded)
    PG_PORTNo5432Postgres port
    PG_USERNoanchorPostgres username
    PG_PASSWORDNopasswordPostgres password
    PG_DATABASENoanchorDatabase name
    USER_SIGNUPNo(not set)Sign up mode: disabled, enabled, or review. If not set, admins can control it via the admin panel
    OIDC_ENABLEDNo—Enable OIDC authentication
    OIDC_PROVIDER_NAMENo"OIDC Provider"Display name for the login button
    OIDC_ISSUER_URLWhen OIDC enabled—Base URL of your OIDC provider
    OIDC_CLIENT_IDWhen OIDC enabled—OIDC client ID
    OIDC_CLIENT_SECRETNo—OIDC client secret. Omit for public client (PKCE)
    DISABLE_INTERNAL_AUTHNofalseHide local login form when OIDC is enabled (OIDC-only mode)
  3. Start the container:

    docker compose up -d
    
  4. Access the app: Open http://localhost:3000

Pre-release (Beta) Image

To test upcoming features before they are officially released, use the next tag:

services:
  anchor:
    image: ghcr.io/zhfahim/anchor:next
    container_name: anchor
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - anchor_data:/data

volumes:
  anchor_data:

Warning: The next image is built from the next branch and may contain incomplete features or breaking changes. Do not use it in production. Back up your data before switching.

Option 2: Building from Source

If you want to build from source or customize the image:

  1. Clone the project:

    git clone https://github.com/zhfahim/anchor.git
    cd anchor
    
  2. Start the container:

    docker compose up -d
    

    The docker-compose.yml file will build the image from source automatically.

Mobile App

Download the Android mobile app.

  1. Visit the releases page: Go to GitHub Releases.

  2. Download the latest release: Multiple APK files are available:

    • Universal APK (anchor-{version}.apk) - Recommended for most users, works on all devices
    • Architecture-specific APKs - Smaller file sizes for specific CPU architectures

OIDC Authentication

Anchor supports OpenID Connect (OIDC) authentication for simplified credential management and streamlined multi-user deployments.

Features

  • Support for standard OIDC providers (Pocket ID, Authelia, Authentik, Keycloak, etc.)
  • Configuration via environment variables or admin settings UI
  • OIDC only mode: disable local username/password login
  • Support for public OIDC clients (PKCE, no client secret required)
  • Auto create users on first login (if user signup is not disabled)
  • Auto link existing users by email

Configuration

Mobile app and Public client

If you want to use OIDC in the mobile app, configure Anchor as a Public client (PKCE, no client secret) in your OIDC provider. Add this redirect URI in your OIDC provider:

anchor://oidc/callback

Required Callback URL (Web)

When configuring your OIDC provider for web login, add this callback/redirect URL:

{APP_URL}/api/auth/oidc/callback

For example, if your Anchor instance is at https://notes.example.com, the callback URL would be:

https://notes.example.com/api/auth/oidc/callback

Environment Variables

Configure OIDC via environment variables in your docker-compose.yml. Pocket ID example:

services:
  anchor:
    image: ghcr.io/zhfahim/anchor:latest
    environment:
      - OIDC_ENABLED=true
      - OIDC_PROVIDER_NAME=Pocket ID
      - OIDC_ISSUER_URL=https://pocketid.example.com
      - OIDC_CLIENT_ID=your-client-id
      - OIDC_CLIENT_SECRET=your-client-secret # Optional for public clients
      - DISABLE_INTERNAL_AUTH=false
      - APP_URL=https://notes.example.com

Admin UI Configuration

Alternatively, configure OIDC via the admin panel (Settings → OIDC Authentication) when the three env vars are not all set.

Backup and Restore

Log into your Anchor deployment, go to Settings, scroll to Export & Import and export Anchor backup (.zip).

The resulting anchor-export-YYYY-MM-DD.zip contains:

  • manifest.json which includes the backup metadata, tags, notes, and attachment references in plain text
  • the referenced attachments, stored within the attachments folder structure

Restore the notes by uploading that file through the web UI. Go to Settings, then scroll down to the Export & Import section.

Troubleshooting & Collecting Logs

Anchor never collects any data. When you need to report a bug, you can collect logs yourself and share them with the maintainer.

Mobile app

  1. Reproduce the issue.
  2. Open Settings → View Logs.
  3. Tap the Export button at the bottom, then share the saved .log file in your bug report.

Sensitive values are stripped before anything is written to the log file. This includes authorization headers, passwords, tokens, refresh tokens, secrets, and email addresses, which are always replaced with ***.

Logs are stored locally on the device only (rolling, ~2 MB max).

Roadmap

Future planned features:

  • Real-time collaboration

Tech Stack

  • Backend: Nest.js, PostgreSQL, Prisma
  • Mobile: Flutter
  • Web: Next.js, TypeScript

Contributing

  1. Fork the repository
  2. Create a feature branch:
    git checkout -b feature/your-feature
    
  3. Make your changes
  4. Ensure builds pass and code is linted:
    • Web: cd web && pnpm build && pnpm check
    • Server: cd server && pnpm build && pnpm check
  5. Commit changes:
    git commit -m "Describe your change"
    
  6. Push and create a Pull Request

Code style

Linting and formatting are enforced in CI and by a pre-commit hook (.githooks/pre-commit) that checks staged files. Running pnpm install in either web or server enables the hook automatically (via the prepare script). To enable it manually:

git config core.hooksPath .githooks

Before committing, fix issues with pnpm check:fix in the relevant project.

Design tokens

The web app's colors, text sizes, spacing, corners, shadows and motion live in design/tokens/ (W3C Design Tokens format). web/app/styles/tokens.css, web/app/styles/notes.css and web/lib/design/tokens.ts are built from them, so change the tokens rather than those files. After changing a token, run this from the repository root (it reads icons from web/node_modules, so run pnpm install in web first):

node design/build/build.mjs

CI runs it with --check and fails if the built files are out of date.

Support

If you find Anchor useful, consider supporting its development:

Buy me a coffee

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL v3) - see the LICENSE file for details.

Significant stargazers

Jan-Erik Rediger

1,035 followers · starred Aug 2026

Benjamin Lupton

1,387 followers · starred Sep 2026

Peter Thaleikis

751 followers · starred Jan 2026

TornaxO7

139 followers · starred Jan 2026