Why Sknerus? • Features • Screenshots
Installation • Configuration • Demo Data
Sknerus is a self-hosted personal finance tracker focused on clarity and speed. Track income and expenses across custom categories, visualize spending trends over time, and get a clear picture of your cashflow — all from a clean, modern interface.
💰 Sknerus (pronounced skneh-roos) is Polish for Scrooge — a penny-pinching miser who knows exactly where every złoty goes. If you're obsessive enough about your finances to self-host a tracker, the name fits.
The original inspiration for this project was ExpenseOwl — a simple self-hosted expense tracker. However, it is no longer actively developed and maintained, and it lacked a few things I needed: multi-chart dashboards, multi-currency support, and a richer data visualization experience.
Sknerus picks up where ExpenseOwl left off. It keeps the philosophy of dead simple, self-hosted, single-user or family expense tracking, while adding:
- A proper analytics dashboard with multiple chart types and time-range navigation
- Table view with grouping and sorting
- Full recurring expense management (create, edit, delete templates)
- Multi-currency support with automatic exchange rate resolution
- A modern SSR React stack (TanStack Start)
It is still not a budgeting app. No accounts, no complex budgets, no bank syncing. Just a fast, honest look at where your money goes.
- Add income and expenses with category, date, amount, currency, optional tags, and free-text notes
- Toggle tags and notes on or off globally from Settings — disabled fields disappear from forms, tables, and cards if you don't use them
- Custom categories with color coding — reorder, rename, or remove them at any time
- Recurring transactions — define a template once, the app materializes entries automatically up to today
- Multi-currency support: record transactions in any currency, configure supported currencies, and exchange rates are resolved and cached automatically. Two providers available: Frankfurter (31 currencies, no key needed) and ExchangeRate-API (165 currencies, free API key required)
- Export and import — bring your data in from any tool or take it anywhere, also from ExpenseOwl
- Configurable fiscal month start date (e.g. set to 5 to count from the 5th of each month)
- Configurable default start page (dashboard or table view)
- Light and dark theme with system-preference detection
- PWA — installable on desktop and mobile for a native-app feel
The dashboard is the heart of the app, organized into four tabs:
- Breakdown — pie chart of spending by category for the selected period, plus cashflow cards showing total income, total expenses, and net balance. Click a category slice to temporarily exclude it from the chart.
- Income vs Expenses — bar chart comparing income and spending month by month, giving a quick cashflow health view over time.
- Monthly — stacked bar chart of expenses across all months, broken down by category, to spot seasonal patterns.
- Trends — category-level trend lines across months to see which spending areas are growing or shrinking.
All dashboard views support flexible time-range navigation: switch between monthly, quarterly, and yearly scopes and step forward/backward through time.
- Chronological list of all transactions for the selected period
- Toggle between flat list and grouped-by-category view
- Inline delete with confirmation
- Add new expenses directly from the table view
- Add, rename, reorder, and delete categories (drag-and-drop ordering)
- Set primary currency and a list of supported currencies for multi-currency entry
- Configure fiscal month start date and default start page
- Toggle visibility of tags and notes fields across the app
- Manage recurring transactions (view, edit, delete templates)
- Export and import all expenses
- Enable optional plugins (see below)
Optional features that extend the core tracker. Toggle them on under Settings → Plugins — they stay invisible until you need them, so the app stays focused for users who only want basic expense tracking.
Track per-vehicle costs alongside your regular expenses. Once enabled, a Vehicles tab appears in Settings where you can:
- Register one or more vehicles (car or motorcycle) with engine size, fuel tank size, fuel type, and starting odometer
- Bind a category to a vehicle so any expense in that category is automatically a vehicle expense
- Pick an expense type per transaction — Fuel, Insurance, Oil change, Purchase, or Accessories — and customize the name, icon, and color of each type per vehicle (the icon/color shows up next to the expense name in tables and cards)
- Record fuel fills with liters, odometer reading, and post-fill tank level to compute real-world L/100km consumption
- Set oil-change intervals in both kilometers and months — the app warns when either threshold is approaching, whichever comes first
- Track insurance and technical inspection expiry dates with status indicators (ok / warning / critical)
- Open the Stats dialog on a vehicle for a fuel history table and a weekly spend-breakdown chart across all expense types
Units are metric: kilometers, liters, L/100km. Imperial units (miles, gallons, MPG) are not currently supported — open an issue if you'd like a metric/imperial toggle.
Click to expand screenshots
The recommended way to run Sknerus is with Docker.
docker run -d \
--name sknerus \
-p 3000:3000 \
-v sknerus-data:/app/.data \
ghcr.io/pnowy/sknerus:latestservices:
sknerus:
image: ghcr.io/pnowy/sknerus:latest
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- ./data:/app/.data
environment:
# Optional — seed demo data on first run (no existing data required)
# SEED_DEMO_DATA: "true"The app will be available at http://localhost:3000.
git clone https://github.com/pnowy/sknerus.git
cd sknerus
pnpm install
pnpm build
node .output/server/index.mjsFor development:
pnpm dev # starts dev server at http://localhost:3000All configuration is done either via environment variables (infrastructure-level) or through the in-app Settings page (user-level).
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Port the server listens on |
DATA_DIR |
.data |
Directory where JSON data files are stored |
SEED_DEMO_DATA |
(unset) | Set to true to seed demo data on first run (see below) |
LOG_LEVEL |
info |
Log verbosity: debug, info, warn, error |
EXCHANGE_RATE_API_KEY |
(unset) | API key for ExchangeRate-API (alternative to setting it in the UI) |
Everything else is configured from the /settings page:
- Categories — add, rename, reorder (drag-and-drop), and delete categories
- Currency — set the primary display currency
- Supported Currencies — currencies available when adding a transaction (exchange rates resolved automatically)
- Exchange Rate Provider — choose between Frankfurter (31 major currencies, no setup) or ExchangeRate-API (165 currencies including MVR, THB, etc. — requires a free API key)
- Start Date — day of month that begins a new fiscal period (default: 1st)
- Start Page — which page loads first: dashboard or table view
- Recurring Transactions — manage recurring income and expense templates
- Export / Import — download all data as CSV or upload a CSV to import transactions. The import modal in the app describes the expected format and supported columns in detail.
- Plugins — enable optional features such as vehicle expense tracking. See the Plugins section above for details.
Sknerus uses a simple file-based JSON storage by default. Data is stored in three files inside DATA_DIR:
expenses.json— all transactionsconfig.json— categories, currency, and app settingsrecurring.json— recurring transaction templatesexchange-rates.json- cache for exchange rates data
Mount DATA_DIR as a persistent volume to retain data across container restarts.
Note: Sknerus does not include authentication. Use a reverse proxy (e.g. Nginx, Caddy, Traefik) with basic auth or SSO in front of it if exposing beyond localhost.
There is a bunch o potential features which could be added if there will interest. Some which I consider but don't need them in my use-case:
- extra storage types (SQL Database – PostgreSQL)
- authentication and authorization
Sknerus ships with a built-in demo data generator that seeds ~2.5 years of realistic family budget data. It is useful for exploring the app before entering your own data.
To enable: set SEED_DEMO_DATA=true and start with no existing data (or a fresh DATA_DIR).
The seed generates:
- 13 categories: Salary, Groceries, Housing, Utilities, Transport, Health, Entertainment, Kids, Dining Out, Clothing, Education, Subscriptions, Motorcycle
- Income: primary salary (with annual raises), partner salary starting a few months in, December bonuses, occasional freelance income
- Fixed costs: rent, internet, streaming subscriptions, gym membership
- Variable costs: groceries (3–4 trips/month), fuel, utilities with seasonal swings (higher in winter), dining out
- Seasonal patterns: clothing peaks in spring/autumn, summer vacation in July, Christmas spending in December, school supplies in August/September
- Sporadic entries: doctor visits, pharmacy, dental, car service, home maintenance
- Vehicle plugin enabled with a Kawasaki Z900 SE motorcycle bought ~14 months ago: purchase, two annual insurance cycles, gear/accessories, ~25 fuel fills with odometer readings (consumption around 6 L/100km), and two oil changes — enough to populate the fuel-history table and the weekly spend-trend chart
Once data exists, the seed is skipped automatically on subsequent starts — safe to leave the flag enabled.
If Sknerus saves you a few clicks (or a few złoty), consider:
- ⭐ Starring the repo — it helps others discover the project
- 🚀 Reporting a bug or suggesting a feature — feedback shapes the roadmap
- 🛠️ Opening a PR — contributions are welcome, big or small
No paid tier, no telemetry, no analytics — just an app I built for myself and shared. A star is the cheapest way to say thanks. 🙏











