Self-hosted service
meceware/wapy.dev avatar
meceware/wapy.dev

wapy.dev: a self hosted subscription tracker built on Next.js and Postgres

Wapy.dev helps you track subscriptions, monitor recurring expenses, and get payment reminders in one powerful and human readable dashboard.

527 stars30 forksJavaScriptNOASSERTION

At a glance

What is it?
Wapy.dev is a subscription and recurring expense tracker you can host yourself, with a Next.js frontend, a Postgres database behind Prisma, email and web push reminders, and a Docker Compose file that runs three containers. The licence is MIT plus the Commons Clause, which is the detail to read before you deploy it as a service.
Who is it for?
Wapy.dev suits someone who wants to see their recurring spending in one place and prefers to host the database themselves, and it does not suit a team that needs shared accounts, receipt scanning or automatic bank import, since none of those appear in the feature list.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 178 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

Editorial analysis

What the tracker actually does, and what it leaves out

Wapy.dev is described as a subscription management platform that helps you track subscriptions, monitor recurring expenses and get payment reminders in one dashboard, and the summary in the package manifest is sharper still: track, manage and optimize your recurring expenses, never miss a payment again.

The feature list is a checklist of a personal finance tool, and reading it tells you the scope. You log recurring subscriptions and payments. You get notified by email, push or webhook when payments are due, and you can customise the notification schedule. You get reports showing your spending across different times and categories. You can mark a payment as paid and review your spending habits over time. You can assign payment methods to subscriptions and see them with icons. You can organise subscriptions into categories with custom colours.

Two features are worth calling out because they change what the tool is for. Multi-currency and timezone support, described as being for managing subscriptions in different currencies and time zones, which matters if your subscriptions are priced in a currency other than your own or billed on a different billing date. And the add to home screen feature, which turns the web app into something that behaves like a mobile app.

What is absent is as informative as what is present. There is no bank import, no receipt scanning, no shared household accounts and no budgeting in the sense of envelopes or categories with limits. The data entry is manual, and the tool is about remembering and seeing rather than about capturing automatically.

That is a reasonable design for a self hosted project, because automated transaction import means holding bank credentials or building a connection to a payments aggregator, and the readme's feature list suggests the author deliberately stopped short of that.

The stack is conventional, which is the point

The tech stack section is worth reading as a decision rather than a list.

Next.js handles both the frontend and the API routes. PostgreSQL is the database, with Prisma as the ORM. Docker is the containerisation. Tailwind does the styling, with shadcn/ui components built on Radix UI. Better Auth handles authentication. The Web Push API does the notifications. And the icons come from Lucide, Dashboard Icons and Simple Icons.

Almost every one of those choices is a mainstream pick, and that is what makes the project useful to self hosters. A Next.js application with a Postgres database and Prisma migrations is something a large number of people can run, debug and upgrade. There is no exotic datastore and no custom build system.

The scripts in the package manifest show the working rhythm.

json
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "migrate": "prisma migrate dev",

There is a postinstall hook that runs a script to fetch dashboard icons, and a clean target that removes node_modules, the generated source directory, the .next build output and the fetched dashboard icons directory. The last one is worth noting: the icons are fetched at install time rather than committed, so a clean build re-downloads them.

The Prisma Studio script opens in the browser on port 5555 with the browser flag set to none, and the Dockerfile exposes 3000 and 5555, so the database browser is reachable in a self hosted deployment. That is a development convenience exposed in a production image, which is a small thing to be aware of.

The repository also has an i18n/ directory, a prisma/ directory with the schema and migrations, a scripts/ directory, a components.json for shadcn, and a docker-compose-dev.yml next to the production compose file.

Three containers, and a cron that pokes the app every minute

The docker-compose file is the clearest description of the running system, and it has three services.

The database is postgres:17.5 with a named container wapydev-db, restart unless-stopped, and a local volume mounted at ./db. The environment block uses defaults for the user and database names with the password coming from the environment file.

yaml
  db:
    container_name: wapydev-db
    image: postgres:17.5
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${POSTGRES_USER:-wapydev}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB:-wapydev}
    ports:
      - '5432:5432'

The application service pulls the published image ghcr.io/meceware/wapy.dev:latest, reads its configuration from .env through env_file, publishes port 3000, and depends on the database.

The third service is the interesting one. It is not an application container but an alpine:3.22 image running a shell loop, and it calls an internal API endpoint once a minute.

yaml
  cron:
    container_name: wapydev-cron
    image: alpine:3.22
    restart: unless-stopped
    command: >
      sh -c 'while true; do
        /usr/bin/flock -n /tmp/wapy.lockfile wget -qO- app:3000/api/cron/;
        sleep 60;
      done'
    depends_on:
      - app

So the reminder scheduling is a polling cron rather than a queue. The flock call is the part with a purpose: it takes a non blocking lock on a file in /tmp, so if the loop is running more than one replica, or if a previous invocation is still going, the second one exits immediately rather than running the same job twice. That is a small piece of engineering that prevents duplicate notifications, and it is the kind of detail you only find by reading the compose file.

The Dockerfile that builds the application is a three stage build on node:24-alpine. The builder stage installs with npm ci --force, runs npx prisma generate, and builds. The runner stage copies the standalone Next.js output, the public directory, the Prisma directory and an entrypoint script, and the image label records the licence as MIT + Commons Clause.

The Commons Clause is the term to read twice

The licence situation is unusual enough that it should be the first thing you check, and it is visible in three places in the repository.

The badge in the readme header says MIT + Commons Clause, the field in the package manifest says MIT+Commons Clause, and the licence field on the repository is listed as a custom one that GitHub cannot classify. The Dockerfile image label also records it as MIT + Commons Clause.

What the combination means in practice is narrower than plain MIT. The MIT part gives you the usual permissions, and the Commons Clause adds a restriction on selling the software. This is a well known pattern in the self hosted world: it exists so that a project can be used freely by individuals and organisations while preventing a hosted version of it from being sold as a service. It is used by a number of open source projects in exactly this position.

The practical consequence for an adopter is straightforward. If you want to run wapy.dev for yourself, on your own infrastructure, for your own data, that is fine. If you were planning to run it as a multi-tenant service for other people and charge them for it, that is what the clause restricts, and you need to read the LICENSE file yourself to see the exact wording rather than relying on a badge. This review does not interpret licence terms.

The other thing the readme does not document is what else is missing. The repository listing shows a Dockerfile, compose files, a .env.example, the Prisma directory and the application source, and there is a wiki linked for getting started and for the environment variables, but the visible documentation does not describe an upgrade path, a backup procedure, or what happens to your data across a major version. For a self hosted service holding your recurring financial data, that gap is worth closing before you put real data in it.

The environment file is thorough. It covers the site URL, the Postgres settings, the email server configuration including the port and the from address, the contact address for the contact form, the Better Auth secret, a switch to disable new user registration, optional GitHub, Google and generic OAuth credentials with the provider name and issuer, the VAPID keys for push, and a separate secret for subscription JWTs. Several of those are marked as automatically generated by the setup script if not given.

Where wapy.dev is the wrong tool

There are four cases where this is the wrong choice, and the honest reason in each case is the same: the tool does not automate anything, and it does not scale past one person.

The first is automatic transaction capture. The data entry is manual, so if you have thirty subscriptions across six services, the initial setup is thirty forms. A tool that pulls transactions from your bank or card and classifies them removes that work entirely. The readme's feature list has no import and no bank connection, and the reason is a sensible one, since bank access means holding credentials or integrating with a payments provider. But it does mean the tool is a tracker rather than a manager, and you should understand that before you migrate your finances into it.

The second is shared household finances. The login options listed are email, GitHub and Google, and the account page is for managing your profile, default notifications and categories. There is no mention of sharing a subscription list with a partner, no shared account, no roles. If two people in a household need to see the same recurring costs, this does not do that.

The third is anything requiring a hosted multi-tenant deployment, which brings back the Commons Clause and also the operational reality. The compose file exposes the database on port 5432 to the host, and the application on 3000, and the Prisma Studio port 5555 is exposed by the image. A public deployment needs that tightened, and a hosted service needs the licence question answered.

The fourth is the boring case: if you want to see recurring spending, a spreadsheet, a bank's own subscription detection, or a general purpose budgeting app will do the same job with less to run.

On the alternative, the difference in approach against a general purpose finance app is where the data lives. A commercial budgeting service knows how to connect to banks because it is their business, and it handles currency conversion, receipt parsing and merchant category codes. Wapy.dev is a database and a web app you run, and it stores what you type with no third party in the middle. The trade is automation and connectivity against control and privacy, and it is a trade that self hosting is supposed to let you make deliberately.

The second alternative is to extend it. The code is a Next.js application with a documented environment file and a setup script, and a fork is a normal fork, as long as the Commons Clause permits what you intend to do with it. That is the path for anyone who wants the reminders but also wants a bank import, and it is the reason the source is open at all.

Editorial conclusion

Wapy.dev suits someone who wants to see their recurring spending in one place and prefers to host the database themselves, and it does not suit a team that needs shared accounts, receipt scanning or automatic bank import, since none of those appear in the feature list. Before you deploy it, read the LICENSE file, because the project is MIT plus the Commons Clause rather than plain MIT, and note that the last push was on 2026-04-28 while the latest release is v2.2.0 from 2026-02-15, so the checked out code and the published image are not the same thing.

Frequently asked questions

What is wapy.dev?

It is a subscription management platform for tracking recurring subscriptions and expenses, with payment reminders by email, push and webhook, multi-currency and timezone support, category management and spending reports. It is designed to be self hosted with Docker.

What licence is wapy.dev released under?

The project is licensed MIT plus the Commons Clause, as recorded in the readme badge, the package manifest and the Docker image label. The licence field on the repository is listed as a custom one that GitHub cannot classify, so read the LICENSE file for the exact terms.

What does the cron container in the wapy.dev compose file do?

It runs an alpine container that calls the app's /api/cron/ endpoint once a minute, using flock to take a non-blocking lock so two replicas do not run the same job at once. It is what drives the scheduled reminders.

How do I install wapy.dev?

The readme points to a Getting Started guide in the project wiki, and configuration is done through a .env file documented on an Environment Variables wiki page. The compose file runs a Postgres 17.5 database, the published app image on port 3000 and the cron container.

Does wapy.dev import transactions from my bank automatically?

No. The feature list covers manual subscription logging, reminders, reports, multi-currency support and payment methods, with no mention of bank import or receipt scanning. The data you see is what you enter.

Official sources

  1. Issues
  2. meceware/wapy.dev on GitHub
  3. Project website
  4. README
  5. Releases
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/meceware-wapy-dev.svg)](https://hysenlabs.com/projects/meceware-wapy-dev)

Was this useful?