Open-source project
gokulkrishh/expense.fyi avatar
gokulkrishh/expense.fyi

expense.fyi: an open-source tracker for expenses, income and subscriptions

Effortlessly track and manage expenses on-the-go with categorisation and logging.

756 stars111 forksTypeScriptAGPL-3.0

At a glance

What is it?
Expense.fyi is a Next.js expense tracker that records incomes, expenses, investments and subscriptions, built on Tailwind and shadcn components with Prisma over Postgres on Supabase, magic link authentication and LemonSqueezy for payments. The README is short and the code carries the detail.
Who is it for?
expense.fyi suits a developer who wants to run their own expense tracker on their own data rather than hand a year of spending to a commercial app, since the database schema and the encrypted fields are yours to inspect. It does not suit someone who wants a polished mobile client today, because the repository is a web application with no native app.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 160 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the application covers

Expense.fyi is an open-source application to track and manage your incomes, expenses, investments and subscriptions. That list is the product definition, and it is broader than the usual expense tracker, which usually stops at spending.

The stack is listed plainly. Next.js is the framework, the components come from shadcn, Tailwind handles the CSS, Supabase is the database, Vercel is the hosting and Resend sends the emails.

The implementation section gives the specifics. The application is built with Next.js from scratch. Postgresql is used as the ORM, which the README phrases as being used for easily communicating with the database for storing user and subscription data, and it points at the Prisma schema in the repository for the details. Supabase is described as an open-source Firebase alternative, with the data stored in the Postgres database, private data encrypted, and magic link authentication provided by Supabase. LemonSqueezy is the payment system, and the README's assessment of it is that its implementation is super simple.

So the interesting design decisions are two. The database is a plain Postgres instance that happens to be hosted by Supabase, which means the ORM layer and the schema are ordinary and the hosted part is only providing infrastructure and auth. And authentication is passwordless, with a magic link, which removes the credential handling that a small self-hosted app would otherwise have to get right.

The routes and the production versus local split

The route table is small and it documents something specific: the application is served on a subdomain in production and on a local hostname in development, and the difference is not just a host name.

| Path | Production | Local | | --- | --- | --- | | Home | / | / | | Signup | app.expense.fyi/signup | app.localhost:3000/signup | | Signin | app.expense.fyi/signin | app.localhost:3000/signin | | Dashboard | app.expense.fyi | app.localhost:3000 |

So the root path is the marketing or landing page, and everything else lives under the app host, which is a common arrangement for a Next.js application with a public site and a signed-in application side by side. The middleware file at the repository root is the piece that would enforce that split, and the local variant relies on the app.localhost convention so a browser treats the app host as a separate origin with its own cookies.

The homepage for the project is expense.fyi, and the GitHub description calls it an open source expense tracker application to track your incomes, investments, subscriptions and expenses.

The author is Gokulakrishnan Kalaikovan, and the repository carries a standard set of contribution instructions: open an issue if you believe you have encountered a bug, and make a pull request to add features, make quality-of-life improvements or fix bugs.

The package scripts and what each one actually does

The package.json is where the operational shape of the project is visible, and it is worth reading because the npm lifecycle hooks do real work here.

json
		"prebuild": "npm run test && prisma format && prisma generate",
		"dbpush": "npm run predev && prisma db push",
		"migrate": "prisma migrate dev --name initial-migration --create-only",

The prebuild hook is the important one. It runs the tests, then formats the Prisma schema, then regenerates the client, all before the actual build. So a broken lint or a type error stops the build, and a stale generated client is impossible.

The database scripts distinguish two workflows. dbpush applies the schema directly to the database without creating a migration, which is the fast path for local development. migrate creates a named migration file with the create-only flag, so the SQL is generated and reviewed before it is applied, which is the path for a shared database.

The checks are split into small pieces and then composed.

json
		"test": "npm run check-lint && npm run check-types",
		"test-all": "npm run check-format && npm run check-lint && npm run check-types && npm run build",

The test script runs lint and type checking, and test-all adds the format check and a full build on top. There are separate format and lint fix scripts, and a format write script that covers the css, js, json, jsx, ts and tsx extensions.

The email side has its own scripts, with a development server on port 3001 and an export command, and there is a .react-email workspace declared, which is where the transactional templates live. The prepare script installs the husky hooks, so the git hooks are wired up on install rather than being a manual step.

The environment variables and the encryption setup

The .env.example file lists eleven variables, and reading them tells you what the application talks to.

The database connection comes first, with a Supabase connection string that includes a connection limit of 1, pgbouncer enabled and sslmode set to require. There is a separate shadow database URL, which is the database Prisma uses to detect drift when it computes a migration, and it is empty by default because it is not needed for the push workflow. The service role key is the privileged Supabase key, kept server side.

The public Supabase URL and anon key are the client-side pair, prefixed with NEXT_PUBLIC_ so the bundler exposes them, and the anon key is the one that is safe in a browser because Supabase's row level security does the actual guarding.

The one to look at twice is PRISMA_FIELD_ENCRYPTION_KEY. The README says private data are encrypted, and this is the key that does it, applied at the ORM layer rather than at the database layer, which is why it sits in the Prisma configuration rather than in a Supabase setting.

The rest are integration keys: the Resend API key for email sending, the public site URL, the LemonSqueezy checkout id for the payment flow, and a Google Analytics 4 id.

Putting it together, the application needs three external services to be fully functional. Supabase for the database and authentication, Resend for email delivery including the magic links, and LemonSqueezy for subscription payments. A self-hosted deployment that skips the payments still gives you the tracker, and one that skips email breaks the sign-in flow.

Where expense.fyi is the wrong choice

The first limitation is that it is a web application, not a mobile one. The repository is a Next.js app with a Tailwind interface and the topics list includes appdir and nextjs-app-directory, but there is no native client in the tree, so tracking your spending from a phone means opening a browser. The topic list also includes supabase, prisma and vercel, which describes a hosted deployment rather than a self-contained application.

The second is the licence. Expense.fyi is under the GNU Affero General Public License Version 3, or any later version, and AGPL has a specific reach: it is the copyleft designed for network software, so a modified version that you run as a service has to offer its source. For a personal tracker that is not a problem, and for a company that wants to fork it into an internal product it is a conversation with legal rather than a technical one.

The third is the dependence on hosted services. Magic link authentication needs email to arrive, which means Resend, and the payments need LemonSqueezy. A self-hosted instance that wants neither has to replace the auth flow, and the README does not describe an alternative.

The fourth is the data model for the investment and subscription tracking, which is the part of the feature list with the least detail in the README. The Prisma schema is linked, so the model is inspectable, but the README spends its space on the stack and the routes, and a reader looking for how an investment is valued over time will not find it there.

The fifth is the maturity signal. The package version is 0.1.0 and marked private, there are no GitHub releases, and the repository's last push was on 2026-05-19. That is a project being built rather than a product being maintained, and the README itself is an introduction without an installation section.

Licence, maintenance and the cost of owning your spending data

The project is under the AGPL-3.0 licence, with the LICENSE file at the root of the repository and the README linking to it as the GNU Affero General Public License Version 3 or any later version.

The repository is not archived and the last push was on 2026-05-19, so the code is being worked on, though at a slower cadence than the fast-moving hosting stack it depends on. The package version of 0.1.0 with private set to true confirms that the npm package is never published, since this is an application rather than a library, and the deployment target is a fork rather than an install.

The cost of running it is the interesting part, because it is small. The application is a Next.js server with a Postgres database, and the two hosted services it leans on are billed per use rather than per seat. Compared with a commercial expense tracker, the ongoing cost is close to the cost of a database, and the data is yours in a database you can query with any Postgres client.

The cost of owning the data is also the feature. An expense tracker holds a record of everything you buy and everything you earn, and the encryption at the ORM layer means the sensitive columns are protected independently of the row level security that guards the table. A project built on Supabase with the same pattern, and a Prisma field encryption key you control, is a reasonable starting point for any application that will hold financial records.

The cost of the dependency stack is what usually decides it. Tailwind, shadcn and Radix for the interface, Prisma and Supabase for the data, Resend for mail and LemonSqueezy for payments, with Vercel as the place it runs. Each of those is a fine choice and each is a vendor, so the question for an adopter is whether the convenience of a working tracker in an afternoon is worth the surface area.

Editorial conclusion

expense.fyi suits a developer who wants to run their own expense tracker on their own data rather than hand a year of spending to a commercial app, since the database schema and the encrypted fields are yours to inspect. It does not suit someone who wants a polished mobile client today, because the repository is a web application with no native app. Read the .env.example before deploying, since the Supabase, encryption and payment variables are all required for the real features, and note that the licence is AGPL.

Frequently asked questions

What is expense.fyi and what does it track?

It is an open-source application to effortlessly track and manage your incomes, expenses, investments and subscriptions. It is built with Next.js from scratch, with Tailwind and shadcn components, Prisma over Postgres, Supabase for the database and magic link authentication, and LemonSqueezy for payments.

Which environment variables does expense.fyi need?

The .env.example lists the Supabase database URL, a shadow database URL, the service role key, the public Supabase URL and anon key, PRISMA_FIELD_ENCRYPTION_KEY for encrypting private fields, the Resend API key, the public site URL, the LemonSqueezy checkout id and a Google Analytics 4 id.

How do I apply the database schema in expense.fyi?

The package scripts offer two paths. dbpush runs prisma format, prisma generate and prisma db push, which applies the schema without a migration file, while migrate runs prisma migrate dev with the initial-migration name and the create-only flag so the migration SQL is generated before it is applied.

What licence is expense.fyi published under?

The GNU Affero General Public License Version 3, or any later version, with the licence file at the root of the repository. AGPL is the copyleft intended for network software, so a modified version run as a service carries source obligations.

Official sources

  1. gokulkrishh/expense.fyi on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gokulkrishh-expense-fyi.svg)](https://hysenlabs.com/projects/gokulkrishh-expense-fyi)

Was this useful?