Personal finance management tool with a modern web dashboard for tracking investments, expenses, cashflow, liquidity, and net worth. Everything is stored locally as Parquet files with zero cloud dependencies.
Tool for my personal finance management with a modern web dashboard. It monitors investments, expenses, cashflow, liquidity, and net worth. Everything is stored locally as Parquet files with zero cloud dependencies.
It follows a scheme similar to Mr Rip spreadsheets.
This is a rewrite in Rust of the original Python project Finguard. It features a modern React frontend and a performant Axum backend. All data processing uses Polars for efficiency and Parquet for storage. Backend rewritten in rust, while the typescript + React frontend has been coded using Lovable
- Investment Tracking: Monitor investments (stocks/ETFs, commodities, bonds) over time with price and quantity history.
- Expense Tracking: Add, edit, delete, and filter monthly expenses with automatic categorization via configurable rules.
- Summary Dashboards: Monthly and cumulative expense breakdowns by primary/secondary category with interactive charts.
- Cashflow: Track salary, interest, dividends, and other income alongside spending. Automatically computes savings and savings rate.
- Net Worth: Keep track of all assets: liquidity, credit/debts, investments (stocks/ETFs, commodities, bonds).
- Recurring Expenses: Define payment templates and apply them to any month; instances are stored per-month separately. Supported via the Expenses → Recurring sub-tab.
- Local-First: All data is stored locally in Parquet files with no external dependencies.
- Modern UI: Built with React, Tailwind CSS, and interactive charts (Recharts).
- Themes: Seven predefined themes with persistent user preference.
Download the docker-compose.yml file and cd into the directory where this file is stored.
Before starting the service the user should set PUID and PGID so files created by the container are owned by the host user. Do one of the following:
- Export in your current shell (temporary for this session):
export PUID=$(id -u)
export PGID=$(id -g)
docker compose up -d
- Or create a persistent
.envfile next todocker-compose.yml. To auto-create it with the current UID/GID:
printf 'PUID=%s\nPGID=%s\n' "$(id -u)" "$(id -g)" > .env
Finally install with (this will pull the latest image if it doesn't already exist locally):
docker compose up -d
Notes:
${HOME}is expanded on the machine wheredocker composeis run. If it is run asroot, then${HOME}may expand to/rootand bind mounts may point to/root/.local/shareand/root/.config.
To update, pull the latest image:
# Pull images for services defined in docker-compose.yml
docker compose pullThen run it
# Start using the pulled image and recreate the container
docker compose up -d --no-build --force-recreateThe UI is available at http://localhost:5173 as soon as the container starts.
# stop and remove
docker compose down- Rust 1.70+ (install from rustup.rs)
- Node.js 18+ and npm (or Bun)
# Clone the repository
git clone https://github.com/Ferrangelo/finguard-rs.git
cd finguard-rs# Run both backend and frontend
./run.shThe UI will be available at http://localhost:5173.
The interface has three main tabs:
| Tab | What it does |
|---|---|
| Expenses | View, add, edit, delete, and filter detailed monthly expenses. Switch to the Summary sub-tab for category breakdowns and charts. The Mappings sub-tab lets you define automatic expense-name-to-category rules. |
| Cashflow | Enter monthly income by category (salary, interest, dividends, other). Spending and savings are auto-calculated from expense data. |
| Net Worth | Track investment holdings and prices, bank/broker liquidity, and credits/debts. View allocation pie charts and evolution over time. |
Use the year and month selectors at the top to switch between periods. All data refreshes automatically.
Data is stored in Parquet files (via Polars) in local XDG-compliant directories:
- Expense & financial data:
$XDG_DATA_HOME/finguard/(default:~/.local/share/finguard/) - Category mappings:
$XDG_CONFIG_HOME/finguard/(default:~/.config/finguard/)
Directory layout per year:
dbs/
└── 2026/
├── 01_detailed_expenses.parquet # January expenses
├── 02_detailed_expenses.parquet # February expenses
├── ...
├── primaries.parquet # Cumulative primary category summary
├── secondaries.parquet # Cumulative secondary category summary
├── cashflow.parquet # Monthly income/spending/savings
├── investments.parquet # Investment holdings
├── investments_prices.parquet # Investment prices
├── liquidity.parquet # Bank accounts & cash
└── credits_debts.parquet # Credits/debts
- No currency exchange: all amounts are assumed to be in a single currency.
- No automatic price updates: investment prices must be entered manually each month.
- No authentication or multi-user support
- No data import/export: no CSV, bank-statement, or spreadsheet import; no export functionality (however the parquet files are always saved to disk).
- Axum: async HTTP framework
- Tokio: async runtime
- Polars: fast DataFrame library
- Serde: JSON serialization
- Parquet: efficient columnar storage
- TanStack Start: React meta-framework
- TanStack Router: client-side routing
- TanStack Query: data fetching & caching
- React Hook Form: form management
- Tailwind CSS: utility-first styling
- Recharts: interactive charts
- TypeScript: type-safe JavaScript
- Vite: lightning-fast dev server
finguard-rs/
├── backend/ # Rust backend
| ├── src/
│ │ ├── main.rs # Axum web server & API handlers
│ │ └── (library modules)
│ ├── Dockerfile
│ └── Cargo.toml # Rust dependencies
│
├── frontend/ # React frontend (TanStack Start)
│ ├── src/
│ │ ├── components/ # UI components
│ │ ├── routes/ # Page routes
│ │ └── services/ # API client
│ ├── Dockerfile
│ └── package.json
├── run.sh # Unified startup script
└── README.md # This file
- Original Python Project:
/home/anferrar/Projects/finguard - Frontend Framework: TanStack Start
- Web Framework: Axum
- Data Processing: Polars
