README.md
<a href="https://wealthfolio.app">Website</a>
·
<a href="https://discord.gg/WDMCY6aPWK">Discord</a>
·
<a href="https://x.com/intent/follow?screen_name=WealthfolioApp">Twitter</a>
·
<a href="https://github.com/afadil/wealthfolio/releases">Releases</a>
Wealthfolio App is a Beautiful and Boring Investment Tracker, with Local Data Storage. No Subscriptions, No Cloud.
Visit the app website at Wealthfolio App.
Wealthfolio features a powerful addon system that allows developers to extend functionality:
Get started building addons: See the Addon Documentation Hub
Documentation for all Activity types, including the required form fields, is available in docs/activities/activity-types.md.
See ROADMAP.md.
Ensure you have the following installed on your machine:
Clone the repository:
git clone https://github.com/afadil/wealthfolio.git
cd wealthfolio
Install dependencies using pnpm:
pnpm install
Setup environment configuration:
Copy the environment template and configure it for your setup:
cp .env.example .env
Update the .env file with your database path and other configuration as
needed:
# Database location
DATABASE_URL=../db/wealthfolio.db
Run in Development Mode:
Build and run the desktop application using Tauri:
pnpm tauri dev
Addon hot reload servers now start only when you explicitly opt in.
For desktop development with Tauri:
VITE_ENABLE_ADDON_DEV_MODE=true pnpm tauri dev
For browser-only development (Vite only, no Tauri):
pnpm dev:addons
You can also set VITE_ENABLE_ADDON_DEV_MODE=true in your .env file to
persist the setting.
Build the application for production:
pnpm tauri build
Run the web UI with a local Axum server with one command.
Setup environment (optional but recommended):
Copy the example environment file and customize it for your setup:
cp .env.web.example .env.web
Edit .env.web to configure database path, ports, and other settings as
needed.
Start both backend and Vite dev server:
pnpm run dev:web
The Vite dev server runs at http://localhost:1420 and proxies API calls to
the Axum backend server.
All configuration is done via environment variables in .env.web.
Server Configuration (WF_* variables):
WF_LISTEN_ADDR - Server bind address (default: 0.0.0.0:8080)WF_DB_PATH - SQLite database path or directory (default: ./db/app.db)
app.db will be used inside itWF_CORS_ALLOW_ORIGINS - Comma-separated list of allowed CORS origins
(default: *). Required when auth is enabled — wildcard * is rejected.
https://wealthfolio.example.comWF_REQUEST_TIMEOUT_MS - Request timeout in milliseconds (default: 30000)WF_STATIC_DIR - Directory for serving static frontend assets (default:
dist)WF_SECRET_KEY - Required 32-byte key used for secrets encryption and JWT
signing
openssl rand -base64 32WF_AUTH_PASSWORD_HASH - Argon2id PHC string enabling password-only
authentication for web modeWF_AUTH_TOKEN_TTL_MINUTES - Optional JWT access token expiry in minutes
(default 60)WF_AUTH_REQUIRED - Set to false to allow starting on non-loopback
addresses without authentication (e.g. when a reverse proxy handles auth)WF_COOKIE_SECURE - Controls the Secure attribute on session cookies
(default: auto)
auto - set Secure only when X-Forwarded-Proto: https is present
(recommended for most reverse-proxy setups)true - always set Secure (use when TLS is guaranteed but the header is
absent)false - never set Secure (plain HTTP without a reverse proxy)WF_SECRET_FILE - Optional path to secrets storage file (default:
<data-root>/secrets.json)WF_ADDONS_DIR - Optional path to addons directory (default: derived from
database path)Vite Configuration:
VITE_API_TARGET - Backend API URL for Vite proxy (default:
http://127.0.0.1:8080)Set WF_AUTH_PASSWORD_HASH to an Argon2id PHC string to require a password
before accessing the Web App.
You can generate the hash with online tools like
argon2.online or the CLI (argon2-utils package):
printf 'your-password' | argon2 yoursalt16chars! -id -e
Tips:
- The first argument is the salt (use 16+ characters); the password is read from stdin.
- Use
printfinstead ofecho -nto avoid hidden newline issues.- For Docker Compose
.env/--env-file, single-quote the hash or double every$($$argon2id$$...).
Copy the full output (starting with $argon2id$...) into .env.web.
Dollar-sign ($) escaping cheat-sheet — Argon2 hashes contain $
characters that shells and Compose interpret as variable references:
| Context | Syntax | Notes |
|---|---|---|
.env.web / app-loaded dotenv | WF_AUTH_PASSWORD_HASH=$argon2id$... | Loaded by the app; no Compose interpolation |
Docker Compose .env/--env-file | WF_AUTH_PASSWORD_HASH='$argon2id$...' | Single quotes prevent Compose interpolation |
Docker Compose .env/--env-file | WF_AUTH_PASSWORD_HASH=$$argon2id$$... | Alternative: double every $ |
| Docker Compose YAML inline | HASH: '$$argon2id$$v=19$$...' | Double every $ to escape Compose interpolation |
docker run (single quotes) | -e HASH='$argon2id$...' | Single quotes prevent shell expansion |
docker run (double quotes) | -e HASH="\$argon2id\$..." | Backslash-escape each $ |
Sessions are cookie-based (HttpOnly, SameSite=Lax, Path=/api). The login
endpoint sets the session cookie automatically — no token is exposed to
client-side JavaScript. Sessions last 60 minutes by default (see
WF_AUTH_TOKEN_TTL_MINUTES).
Reverse proxy (HTTPS): If your reverse proxy terminates TLS, ensure it
forwards X-Forwarded-Proto: https so the server sets the Secure cookie
attribute correctly. Alternatively, set WF_COOKIE_SECURE=true to always set
Secure. See WF_COOKIE_SECURE above.
.env.web are loaded automatically by the
dev:web scriptRun just the HTTP server without the Vite dev server (from repo root):
cargo run --manifest-path apps/server/Cargo.toml
The server accepts the same WF_* environment variables as documented in the
Web Mode Configuration section above. You can set them inline
or via .env.web:
WF_LISTEN_ADDR=127.0.0.1:8080 WF_DB_PATH=./db/app.db cargo run --manifest-path apps/server/Cargo.toml
See Web Mode Configuration for a complete list of supported environment variables.
You can either pull the official Docker image or build it yourself locally.
The latest server build is published to Docker Hub.
docker pull afadil/wealthfolio:latest
After pulling, use afadil/wealthfolio:latest in the run commands below. If you
build the image locally, swap the image name back to wealthfolio.
Build the Docker image directly from source (no pre-build required):
docker build -t wealthfolio .
The build process:
pnpm install + pnpm vite build)cargo build --release)The final image includes:
/app/distwealthfolio-server binary at /usr/local/bin/wealthfolio-serverYou can configure the container using either:
-e flag)--env-file flag)Option 1: Create an environment file (recommended for production):
# Create a Docker-specific environment file
cat > .env.docker << 'EOF'
WF_LISTEN_ADDR=0.0.0.0:8088
WF_DB_PATH=/data/wealthfolio.db
WF_SECRET_KEY=<generate-with-openssl-rand>
WF_CORS_ALLOW_ORIGINS=https://wealthfolio.example.com
WF_REQUEST_TIMEOUT_MS=30000
WF_STATIC_DIR=dist
EOF
Generate and add your secret key:
echo "WF_SECRET_KEY=$(openssl rand -base64 32)" >> .env.docker
Option 2: Use inline environment variables (simpler for testing):
See examples below for inline configuration.
All examples below use the published image (afadil/wealthfolio:latest). If you
built locally, substitute your local tag (e.g., wealthfolio).
Using environment file (recommended):
docker run --rm -d \
--name wealthfolio \
--env-file .env.docker \
-p 8088:8088 \
-v "$(pwd)/wealthfolio-data:/data" \
afadil/wealthfolio:latest
Basic usage (inline environment variables):
docker run --rm -d \
--name wealthfolio \
-e WF_LISTEN_ADDR=0.0.0.0:8088 \
-e WF_DB_PATH=/data/wealthfolio.db \
-p 8088:8088 \
-v "$(pwd)/wealthfolio-data:/data" \
afadil/wealthfolio:latest
Development mode (with CORS for local Vite dev server):
docker run --rm -it \
--name wealthfolio \
-e WF_LISTEN_ADDR=0.0.0.0:8088 \
-e WF_DB_PATH=/data/wealthfolio.db \
-e WF_CORS_ALLOW_ORIGINS=http://localhost:1420 \
-p 8088:8088 \
-v "$(pwd)/wealthfolio-data:/data" \
afadil/wealthfolio:latest
Production with encryption (recommended):
docker run --rm -d \
--name wealthfolio \
-e WF_LISTEN_ADDR=0.0.0.0:8088 \
-e WF_DB_PATH=/data/wealthfolio.db \
-e WF_SECRET_KEY=$(openssl rand -base64 32) \
-p 8088:8088 \
-v "$(pwd)/wealthfolio-data:/data" \
afadil/wealthfolio:latest
The container supports all WF_* environment variables documented in the
Web Mode Configuration section. Key variables:
WF_LISTEN_ADDR - Bind address (must use 0.0.0.0:PORT for Docker, not
127.0.0.1)WF_DB_PATH - Database path (typically /data/wealthfolio.db)WF_CORS_ALLOW_ORIGINS - CORS origins (set for dev/frontend access)WF_SECRET_KEY - Required 32-byte key used for secrets encryption and JWT
signing/data - Persistent storage for database and secrets
/data/wealthfolio.db/data/secrets.json (encrypted with WF_SECRET_KEY)8088 - HTTP server (serves both API and static frontend)Access the application at http://localhost:8088 after starting the container.
Important: The server must bind to 0.0.0.0 (all interfaces) inside the
container to be accessible from your host machine. Binding to 127.0.0.1 will
make the app only accessible from within the container.
For a consistent development environment across all platforms, you can use the provided DevContainer configuration. This method requires fewer manual setup steps and provides an isolated environment with all necessary dependencies.
Clone the repository (if you haven't already):
git clone https://github.com/afadil/wealthfolio.git
cd wealthfolio
Open in VS Code:
Launch DevContainer:
F1 or Ctrl+Shift+PWait for container build:
Start Development:
Wealthfolio supports a powerful addon ecosystem that allows developers to extend functionality with custom features.
Create a new addon:
npx @wealthfolio/addon-dev-tools create my-addon
cd my-addon
npm install
Start development server:
npm run dev:server
Start Wealthfolio in addon development mode (in another terminal):
VITE_ENABLE_ADDON_DEV_MODE=true pnpm tauri dev
Your addon will be automatically discovered and loaded with hot reload support!
Check out the addons/ directory for sample addons including:
wealthfolio/
├── apps/ # Application packages
│ ├── frontend/ # React frontend application
│ │ ├── src/ # Source code
│ │ │ ├── adapters/ # Environment adapters (Tauri/Web)
│ │ │ ├── addons/ # Addon system runtime
│ │ │ ├── components/ # React components
│ │ │ ├── features/ # Feature modules (self-contained)
│ │ │ ├── pages/ # Application pages and routes
│ │ │ ├── hooks/ # Custom React hooks
│ │ │ └── lib/ # Utility libraries and helpers
│ │ ├── public/ # Static assets
│ │ ├── index.html # HTML entry point
│ │ └── vite.config.ts # Vite build config
│ ├── tauri/ # Tauri desktop/mobile app (Rust IPC commands)
│ └── server/ # Axum HTTP server for web mode
├── crates/ # Rust crates (shared backend logic)
│ ├── core/ # Core business logic, services, models
│ ├── storage-sqlite/ # SQLite storage layer (Diesel ORM)
│ ├── market-data/ # Market data providers
│ ├── connect/ # External service integrations
│ └── device-sync/ # Device sync functionality
├── addons/ # Example addons
│ ├── goal-progress-tracker/ # Goal tracking addon
│ ├── investment-fees-tracker/ # Fees tracking addon
│ └── swingfolio/ # Trading addon
├── packages/ # Shared TypeScript packages
│ ├── addon-sdk/ # Addon SDK for developers
│ ├── addon-dev-tools/ # CLI and dev server for addons
│ └── ui/ # Shared UI components (@wealthfolio/ui)
├── docs/ # Documentation
│ ├── addons/ # Addon development docs
│ ├── activities/ # Activity types docs
│ └── architecture/ # Architecture docs
├── e2e/ # End-to-end tests
├── scripts/ # Build and dev scripts
├── Cargo.toml # Rust workspace config
├── package.json # Node.js dependencies
├── pnpm-workspace.yaml # pnpm workspace config
└── tsconfig.json # TypeScript config
All your financial data is stored locally using SQLite database with no cloud dependencies:
API credentials are securely stored using the operating system keyring through
the keyring crate:
set_secret and get_secret commands for external servicesctx.api.secrets) for addon-specific
sensitive dataAddons operate under a comprehensive permission system:
Contributions are welcome! Please follow these steps:
git checkout -b feature-branch).git commit -m 'Add some feature').git push origin feature-branch).This project is licensed under the AGPL-3.0 license. See the LICENSE file for
details.
Brand assets in assets/brand/ are trademarks; see
TRADEMARKS.md.
Wealthfolio and the Wealthfolio logo are trademarks of Teymz Inc. The code is licensed under AGPL-3.0; trademarks are not granted under that license.
Enjoy managing your wealth with Wealthfolio! 🚀