A private, local-first personal-finance desktop app — track wallets, movements, transfers, recurring bills, savings, goals, budgets and portfolios entirely on your own machine. No cloud, no accounts, no sign-up.
Native desktop app built with Tauri 2 + React + TypeScript, talking directly to a local SQLite database. Your data never leaves your computer unless you explicitly turn on optional online price lookups (see Privacy & network).
Copyright © 2026 AlexDevFlow · Licensed under GPL-3.0-or-later (see LICENSE).
Grab the installer for your OS from the Releases page.
The binaries are not code-signed (this is a free, open-source app), so each OS shows a one-time "unknown developer" warning on first launch. That's expected — here's how to get past it:
Works on both Intel and Apple Silicon. Paste into Terminal:
curl -fsSL https://raw.githubusercontent.com/AlexDevFlow/yfine2/main/scripts/install-macos.sh | bashIt downloads the latest universal .dmg, installs Yfine.app into /Applications
and opens it — with no Gatekeeper detour, because a file fetched by curl never gets
the quarantine flag in the first place. (Read the script
before running it; that's worth doing for any curl | bash.)
Flags go after -s --, e.g. … | bash -s -- --force to replace an existing install
without being asked. Also --dest "$HOME/Applications", --tag v0.1.0, --no-launch.
Universal build (Intel + Apple Silicon). Open the .dmg, drag Yfine to
/Applications. Since the app is unsigned, macOS blocks the first launch — how you
unblock it depends on your version:
- macOS 15 (Sequoia) and later: open System Settings → Privacy & Security, scroll down to Security, and click Open Anyway next to Yfine. The old Control-click → Open shortcut no longer overrides Gatekeeper.
- macOS 14 (Sonoma) and earlier: Control-click the app → Open → Open.
- Any version, from Terminal:
xattr -dr com.apple.quarantine /Applications/Yfine.app
Run the installer. SmartScreen may say "Windows protected your PC" → click More info → Run anyway.
- AppImage:
chmod +x Yfine_*.AppImagethen run it. - Debian/Ubuntu:
sudo dpkg -i Yfine_*.deb(or open with your package manager).
- Dashboard — net worth per currency (+ optional consolidated total), this-month in/out/saved, monthly-flow chart, recent movements, and a 90-day cashflow forecast.
- Sources — multi-currency accounts with derived balances, savings funds, periodic yield.
- Movements — in/out, cross-currency transfers, split transactions, filters, grouped by day, bulk edit (delete/move).
- Recurring — auto/confirm schedules with a background reconciliation on launch.
- Budgets / Goals / Whims — tag budgets with rollover, savings goals, prioritised wishlist.
- Portfolios — holdings with FX-correct valuation; optional live prices (off by default).
- Data —
.yfine/JSON backup & restore, CSV bank import (Revolut/N26/YNAB/PayPal/Firefly), CSV / Excel / PDF export. - Security — optional password with AES-256-GCM at-rest encryption (PBKDF2; also reads legacy Fernet archives).
- Light/dark themes, four languages (en/it/es/uk), ⌘K command palette.
Yfine stores everything in a local SQLite database in your OS app-data directory — nothing is uploaded. If you set a password, the database is encrypted at rest (AES-256-GCM) and decrypted into a working file only while the app is open.
It keeps the same schema as the original Yfine, so an existing yfine.db (or an
encrypted yfine.db.enc) migrates unchanged: the drift-tolerant migrator adds any
missing tables/columns additively and never drops data.
Yfine sends no telemetry and makes zero network requests by default. Everything works fully offline.
Three opt-in features reach the internet only when you turn them on:
- Live prices (portfolios): fetches quotes from CoinGecko and Yahoo Finance.
- On-chain balance watch: queries a public blockchain RPC (blockstream.info for BTC, a public Ethereum RPC, Solana mainnet) for an address you add. Note that this sends the public wallet address you're watching to that third-party endpoint, which can correlate it with your IP. Don't enable it if that matters to you.
- Update check (Settings → Updates): asks GitHub whether a newer release exists.
A manual "Check for updates" button is always available; an optional toggle also
checks once on launch. Both are off until you ask — nothing downloads or
installs without your confirmation, and with no connection it simply reports that
the update server couldn't be reached. (On Linux, in-app updates apply to the
.AppImagebuild;.debusers update by re-downloading.)
The portfolio screen can also embed a TradingView chart widget, which loads from TradingView when shown.
No accounts, no analytics, no background phone-home.
Prerequisites: Rust (stable), Node 20+, pnpm 10+, and the Tauri 2
platform dependencies for your OS (on Debian/Ubuntu: libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf build-essential). See the
Tauri prerequisites guide.
pnpm install
pnpm tauri build # installers land in src-tauri/target/release/bundle/pnpm dev # browser preview at http://localhost:1420 (in-memory sql.js, seeded sample data)
pnpm tauri dev # the real native window (SQLite on disk); first run compiles Rust
pnpm test # vitest — domain + repositories
pnpm typecheck # tsc --noEmitThe browser preview uses an in-memory sql.js database so the whole UI is explorable without the native runtime. The packaged app uses native SQLite.
CI (.github/workflows/release.yml) builds Linux,
Windows, and a universal macOS installer on a v* tag, then creates a draft
GitHub Release with the artifacts attached. Steps:
- Bump the version in all three manifests so they match the tag:
package.json,src-tauri/tauri.conf.json, andsrc-tauri/Cargo.toml. - Commit, then tag:
git tag v0.1.0 && git push origin v0.1.0(or trigger the workflow manually via Actions → Run workflow). - Wait for all three OS builds to finish, then review and publish the draft Release.
- Sanity-check that each installer launches on its OS before announcing.
Binaries are unsigned by design; the install instructions above cover the first-launch bypass.
In-app updater (optional). For the Settings → Updates feature to deliver updates,
the release must be signed and ship a latest.json asset. CI does this
automatically when two repository secrets are set
(Settings → Secrets and variables → Actions):
TAURI_SIGNING_PRIVATE_KEY— contents of the minisign private key frompnpm tauri signer generate. Keep it safe and never commit it; losing it means existing installs can no longer verify updates. The matching public key is already baked intosrc-tauri/tauri.conf.json(plugins.updater.pubkey).TAURI_SIGNING_PRIVATE_KEY_PASSWORD— the key's password (set it to an empty value if the key has none).
If the secrets are absent the build still succeeds — it just ships installers without update metadata, and the in-app check reports "up to date". The updater resolves the latest published (non-draft) release, so updates go live only after you publish.
GPL-3.0-or-later. You're free to use, study, modify, and redistribute it; redistributed versions must remain under the same license and offer their source.





