Currency and Exchange Rates
Cashlytics supports multi-currency display, transaction metadata, and a converter tool. Since 0.8.13, all totals (dashboard, analytics, forecast, reserves, insights, and the AI tools) are converted with live exchange rates. The static table in src/lib/currency.ts is only the last fallback.
Settings
User settings store locale and base currency (table user_settings, read server-side in src/lib/user-preferences.ts). Defaults come from NEXT_PUBLIC_DEFAULT_LOCALE and NEXT_PUBLIC_DEFAULT_CURRENCY when no user-specific setting exists. These are build-time variables: they are baked into the image and cannot be changed with the published Docker image.
Supported Currencies
The supported currency list is defined in src/lib/currency.ts and includes EUR, USD, JPY, GBP, CNY, CHF, AUD, CAD, HKD, SGD, KRW, MXN, INR, NZD, SEK, NOK, PLN, TRY, ZAR, BRL, and DKK.
Exchange Rate Source
src/lib/exchange-rates.ts fetches EUR-based rates from the Frankfurter API (https://api.frankfurter.app/latest?base=EUR&symbols=...) and persists them in the exchange_rates table (unique base/target, rate, fetched_at).
Caching works in layers:
- In-memory cache per process: 1 hour. Concurrent requests share one pending fetch, and
getRatesis cached per request. - Database cache: 24 hours.
- API timeout: 5 seconds.
- After a failed API call, the next refresh attempt is delayed by 15 minutes.
Fetch priority is:
- fresh in-memory or database cache
- Frankfurter API refresh when stale or empty
- stale database cache if the API is unavailable
- built-in fallback rates
The root layout loads the rates once and passes them to the client, so the Tools page and all totals use the same values.
API
GET /api/exchange-rates returns current rates with EUR as base as a flat object ({ "EUR": 1, "USD": ... }), or 500 with { error }. It requires a session. No bundled client calls this endpoint; it is only useful for external use.
Transaction writes can store original amount, saved currency, and exchange rate metadata so later display does not depend only on current rates.