# Ocular is a self-hosted budget tracker where the interesting part is the year-over-year data model

> Ocular is a Vue 3 personal finance app for tracking budgets across multiple years, with a Sankey diagram, an all-time overview, carry-over between years, inline expression evaluation, Google Sheets import and a privacy mode. The backend is a Go service called Genesis, the frontend is a Vite app, and the whole thing ships as one container image.

**simonwep/ocular** — 💰 Ocular - A fancy, simplistic, beautiful and straight-forward, open-source budgeting tracking app to track your budget across the years. Easy to use, to get started and to set up.

- Repository: https://github.com/simonwep/ocular
- Website: https://simonwep.github.io/ocular
- Stars: 575 · Forks: 51
- Language: Vue
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/simonwep-ocular

## A frontend and a Go backend, not a single Vue app

Ocular is described in the repository listing as a fancy, simplistic, beautiful and straight-forward, open-source budgeting tracking app to track your budget across the years, and the primary language is Vue. The README's own tagline is that it helps you see your budgets more clearly.

The repository layout shows two applications and a set of supporting pieces. There is a src/ directory for the Vue frontend, a genesis/ directory for the backend, and the backend is Go, since the development script starts it with go -C genesis run . start. The frontend runs on Vite with vite --host, and the production build is vue-tsc for the type check followed by vite build.

The dependencies describe the frontend's shape: vue 3.5.42 with vue-router 5.3.1 and vue-i18n 11.4.10 for the internationalisation, echarts 6.1.0 for the charts, @vueuse/core and @remixicon/vue for utilities and icons, papaparse for parsing the Google Sheets import, and yuppee for validation.

So there is a real separation of concerns here, a Vue single page application talking to a Go service. That is a heavier architecture than a purely client side budget app, and the README explains why: user management and authentication via app and CLI, which a browser-only app with local storage cannot do.

## The multi-year model is the feature that justifies the backend

Most budget apps model one budget period. Ocular's feature list includes track budgets across multiple years, an all-time overview of your budgets including analytics, and carry over budgets to the next year. The screenshots section confirms this shape, with separate dashboard, dashboard yearly overview and all-time overview images.

The all-time overview is the interesting consequence. Once you keep several years of data, you can ask where the money actually went, and the dashboard feature says extensive statistics and multiple charts including a Sankey diagram. A Sankey diagram is a flow diagram, so you are looking at how income is distributed into categories, which is a different question from a pie chart of spending by category.

The carry-over feature is the other structural piece. A financial year is customizable, with a start at any month, and budgets can carry over to the next year. That combination is what a spreadsheet struggles with and what a monthly app cannot express, since the year boundary and the budget period are not the same thing.

Two smaller features are worth noting for their design. Inline expression evaluation means you can put a formula directly into a budget field, so a category can depend on another one rather than on a number you retyped each month. And privacy mode is for when you are in a public place, which is a small feature that says the author has thought about using the app on a laptop in a cafe.

## Hybrid mode and the .env file decide who can see your budget

The .env.example at the repository root is the clearest documentation of the authentication model, and it deserves reading carefully before you deploy anything.

There is a frontend development configuration with a comment saying the backend host is usually /api if hosted locally and used via proxy. And there is an explicit note: if OCULAR_HYBRID_MODE is not set to true, authentication will be required to use the app. The variable is empty by default in the example file, which means authentication is required.

Setting OCULAR_HYBRID_MODE to true makes it possible to use the app without authentication. That is clearly a development convenience, and it is also the single most dangerous setting in the project, because an unauthenticated budgeting application on a reachable network exposes your financial data to anyone who finds the URL.

The example file looks like this, with the comment lines left in place:

```bash
OCULAR_GENESIS_HOST=/api

OCULAR_HYBRID_MODE=

OCULAR_TEST_USERNAME=admin
OCULAR_TEST_PASSWORD=hgEiPCZP
OCULAR_BUILD_VERSION=dev
OCULAR_BUILD_SHA=unknown
OCULAR_BUILD_DATE=2022-03-24T17:38:03.000Z
"""
```

The second and third values are the optional pre-filled login credentials for local testing, and the last three are build metadata placeholders, the last of which holds a timestamp of 2022-03-24 in the example file.

Because the file is an example and not a real deployment configuration, those values are placeholders. The point for a deployer is that the .env file is where the decision about authentication gets made, and that the default is the safe one.

## The release train is seasonal, and one release was a security update

The release history is short and named for what it contains rather than for a version number alone. v2.3.0 is a Spring Stability Update from 2026-04-03, v2.4.0 is a Summer Feature and Design Update from 2026-06-13, and v2.4.1 is a Security Update from 2026-09-05.

That last one is the fact worth holding onto. A project that ships a release labelled only as a security update, without a feature list, is telling you the priority was fixing something. The README does not say what was fixed, so a reader has to go looking in the release itself.

The cadence, roughly two releases a year on a seasonal cycle, is consistent with a project maintained by one person. The README's first feature bullet says the app is handcrafted and that no AI was used during development, except for translations, and the package metadata names a single author, Simon Reinisch, with pnpm 11.25.0 as the package manager and Node 24.12.0 or later required.

There is no GitHub releases list to browse in the repository listing, but the README points to the releases page for the latest release with its feature list, to milestones for upcoming features in the next minor versions, and to the documentation site for everything else, including a fully featured demo and separate pages for a quickstart and deployment.

The licence is MIT, with a LICENSE file at the root, so there is no copyleft obligation on a self-hosted deployment. That is a licensing note rather than legal advice.

## One container, a Docker image and a hosted demo to compare against

The deployment story is deliberately short. The README says Ocular is deployed as a single container and the images are uploaded under the packages section of the repository, with a badge linking to the Docker image pulls. There is a docker/ directory at the root and a .dockerignore, and the documentation has a Deploy it page.

The interesting operational detail is that the project also offers a hosted one-click option through PikaPods, with a run button badge in the README. That is unusual for a self-hosted project, and it is worth understanding why it is there. For someone deciding whether to run this at all, the hosted instance is a zero-commitment way to see whether the data model fits, and the same codebase runs either way, which is a genuine advantage over a product where self-hosting is a different codebase.

For the local development loop, the scripts in package.json show the shape. The dev script fans out to the dev: prefixed scripts, so dev:frontend and dev:backend run together, the backend being the Go service started from the genesis directory. The build script type checks with vue-tsc and then builds with Vite.

Testing is split too, with test:unit running vitest and test:e2e running Playwright, and a playwright.config.ts at the root. The test:e2e:ui variant gives the interactive mode, and test:all chains lint:fix, build, test:unit and test:e2e.

There is also a scripts/ directory with three maintenance tasks worth noting, because they show what the project treats as recurring work: scripts:currencies updates currency data, scripts:screenshots regenerates the screenshots, and scripts:localize runs the translation pipeline. The i18n and multi-currency support in the feature list is therefore maintained by tooling rather than by hand.

## Where a spreadsheet or a hosted app is the better answer

The first limitation is that this is a personal finance app, and a personal finance app is a product with a lifetime of support obligations that a self-hosted single maintainer project cannot always meet. The seasonal release pattern and the one security-focused release suggest the author is doing maintenance around a job rather than running a support queue. If you need someone to answer an email when a release breaks your import, that is not this repository.

The second limitation is the data source. There is no bank sync in the feature list. The import path is Google Sheets annual planner, plus JSON export. So getting data in is manual, and if your bank is not the one the author uses, you will be transcribing numbers by hand, which is the part of budgeting nobody enjoys. A tool that connects to your accounts and classifies them does the work that Ocular leaves to you.

The third is scope of analysis. The Sankey diagram and the yearly overview are the strong parts, and they are about how your own recorded numbers relate to each other. They are not forecasting, not net worth tracking across assets you hold outside the app, and not anything about shared household budgets with permissions, which is what a product like this often needs to grow into.

The alternative to weigh is a self-hosted instance of a more conventional personal finance tool, or a hosted service. Both give you bank connectivity and a support path. What Ocular gives that they do not is the multi-year budget model with carry-over, in a codebase you can read, with a Go backend that exposes a CLI for user management, and the freedom to keep your financial records on your own machine.

The privacy argument cuts both ways here. A self-hosted instance keeps the data on your hardware, which is the point of the project, but it also means you own the upgrade path, the database backup, and the security patches, including the one shipped as v2.4.1.

## Conclusion

Adopt Ocular if you want to self-host your budget data and track spending across years rather than one budget period at a time, since the multi-year model and the carry-over behaviour are the parts a spreadsheet does not give you. Do not adopt it if you want a hosted product with a support team, since it is a single maintainer project and the security release history shows security work is done reactively. Verify first how the authentication modes behave, because the hybrid mode disables authentication entirely, and that the container image you pull is the one you want, since the package is published as a single container.

## FAQ

### What is Ocular and what does it track?

Ocular is a self-hosted personal finance and budget tracking app that tracks budgets across multiple years, with a customizable financial year starting at any month, carry over of budgets to the next year, an all-time overview with analytics, a dashboard with multiple charts including a Sankey diagram, inline expression evaluation and a privacy mode.

### How do I run Ocular in development?

The dev script fans out to the dev: prefixed scripts, so the frontend starts on Vite with vite --host and the backend starts with go -C genesis run . start. The backend host for the frontend is configured through OCULAR_GENESIS_HOST, which is usually /api when hosted locally and used via a proxy.

### Does Ocular require authentication?

By default yes. The .env.example states that if OCULAR_HYBRID_MODE is not set to true, authentication will be required to use the app, and the variable is empty by default. Setting it to true allows using the app without authentication, which is a development convenience and a deployment risk.

### How is Ocular deployed?

As a single container, with the images uploaded under the packages section of the repository and a badge linking to the image pulls. The documentation has a separate deploy page, and the README also offers a hosted one-click option through PikaPods for trying the app without running it yourself.

### Can I import my budget data into Ocular?

The feature list says you can import your data from Google Sheets annual planner and export as JSON. The dependency on papaparse in the frontend package is consistent with parsing a spreadsheet, and the scripts directory includes a localizer task for the translation pipeline and a currency update task.

## Sources

- [License: MIT](https://github.com/simonwep/ocular/blob/main/LICENSE)
- [Project website](https://simonwep.github.io/ocular)
- [README](https://github.com/simonwep/ocular/blob/main/README.md)
- [Releases](https://github.com/simonwep/ocular/releases)
- [simonwep/ocular on GitHub](https://github.com/simonwep/ocular)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/simonwep-ocular
