Skip to content

Repository files navigation

Sknerus Logo

Sknerus

CI Publish Latest Release License

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.

Sknerus App Preview


Why Sknerus?

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.

Features

Core Functionality

  • 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

Dashboard

The dashboard is the heart of the app, organized into four tabs:

  1. 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.
  2. Income vs Expenses — bar chart comparing income and spending month by month, giving a quick cashflow health view over time.
  3. Monthly — stacked bar chart of expenses across all months, broken down by category, to spot seasonal patterns.
  4. 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.

Table View

  • 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

Settings

  • 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)

Plugins

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.

Vehicle 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.

Screenshots

Click to expand screenshots
Page View
Desktop - Dashboard – Breakdown (light)
Desktop - Dashboard – Income vs Expenses (dark)
Desktop - Dashboard – Monthly (light)
Desktop - Dashboard – Trends (dark)
Mobile - Table view
Desktop - Table View
Desktop - Table View (group by category)
Desktop - Settings
Desktop - Vehicle Settings
Desktop - Vehicle Stats

Installation

The recommended way to run Sknerus is with Docker.

Docker CLI

docker run -d \
  --name sknerus \
  -p 3000:3000 \
  -v sknerus-data:/app/.data \
  ghcr.io/pnowy/sknerus:latest

Docker Compose

services:
  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.

Building from Source

git clone https://github.com/pnowy/sknerus.git
cd sknerus
pnpm install
pnpm build
node .output/server/index.mjs

For development:

pnpm dev   # starts dev server at http://localhost:3000

Configuration

All configuration is done either via environment variables (infrastructure-level) or through the in-app Settings page (user-level).

Environment Variables

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)

In-App Settings

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.

Data Storage

Sknerus uses a simple file-based JSON storage by default. Data is stored in three files inside DATA_DIR:

  • expenses.json — all transactions
  • config.json — categories, currency, and app settings
  • recurring.json — recurring transaction templates
  • exchange-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.

Considered features

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

Demo Data

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.

Show Your Support

If Sknerus saves you a few clicks (or a few złoty), consider:

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. 🙏

About

Simple, self-hosted expense tracker with a beautiful UI.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages