Self-hosted service
kittendevv/Invio avatar
kittendevv/Invio

Invio: Self-Hosted Invoicing Without the Bloat

Self-hosted invoicing without the bloat.

1,188 stars143 forksTypeScriptUnlicense

At a glance

What is it?
Invio is a TypeScript invoicing application you run on your own hardware and share with clients by link. It is small, opinionated, and honest about its scope, but the README leaves deployment details to a wiki.
Who is it for?
Adopt Invio if you want a self-hosted invoice tool with a small surface area and you are comfortable reading the wiki before you expose it to the internet. Skip it if you need accounting integrations, tax filing, or multi-currency reconciliation; the README describes none of those.
Can I use it commercially?
Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 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 September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Invio Is and Who It Is Built For

Invio is described as "Selfhosted invoicing without the bloat." The repository is a TypeScript project with a SvelteKit frontend and a backend, packaged as a single Docker image. It targets people who send invoices and want to stop paying a subscription for the privilege: freelancers, small studios, and anyone who already runs a home server or a VPS.

The design decision that shapes everything else is the client experience. The README says clients should not need an account and should receive a secure link instead. That removes user management from the product surface entirely. There is no client portal to build, no password reset flow for customers, and no reason to store client credentials. The trade-off is that the invoice link becomes the access control, so the security of that link is the security of the invoice.

The second decision is scope. The README lists no accounting ledger, no bank sync, no expense tracking, and no tax engine. Invio creates an invoice, shares a link, and records payment. If your workflow needs double-entry bookkeeping, this is not it.

How the Pieces Fit Together

The repository layout shows two applications: backend/ and frontend/. The Dockerfile builds the frontend with Bun, then copies the output into a Debian 12 runtime that also carries Deno, Python 3, and weasyprint. Supervisor runs the processes inside the container, which is why the image exposes a single port, 8000, rather than separate frontend and backend ports.

The .env.example confirms the split. BACKEND_PORT defaults to 3000 and FRONTEND_PORT to 8000, and BACKEND_URL tells the frontend where to reach the backend. In Docker Compose the example value is http://backend:3000; for local development it is http://localhost:3000. The frontend is a SvelteKit application, and ORIGIN is required because SvelteKit uses it for CSRF protection. TRUSTED_ORIGINS is optional and accepts a comma-separated list, with glob support such as http://*.ts.net:8003, or "*" to allow all on trusted networks.

Persistence is a single SQLite file. DATABASE_PATH defaults to /app/data/invio.db inside Docker and ./invio.db for local development, and the Compose file mounts a named volume, invio_data, at /app/data. That means backups are a file copy, and there is no database server to administer. PDF generation is handled by weasyprint, which is installed in the image along with fonts-dejavu, fonts-liberation, and fonts-noto. WEASYPRINT_BIN exists only for non-standard paths; the documentation states normal paths are checked automatically.

Installing Invio with Docker Compose

The repository ships a docker-compose.yml that pulls ghcr.io/kittendevv/invio:latest, reads variables from a .env file, mounts the data volume, and maps port 8000. Start by copying the example environment file, since the Compose file expects .env to exist.

bash
cp .env.example .env

The README says only three values are required: ADMIN_USER, ADMIN_PASS, and JWT_SECRET. ORIGIN is also present in the example and is described as required for SvelteKit CSRF protection. Set ORIGIN to the address where you will actually reach the app, because a mismatch here will make form submissions fail.

bash
ADMIN_USER=admin
ADMIN_PASS=supersecret
JWT_SECRET=change-me-in-production
ORIGIN=http://localhost:8000

Then bring the stack up. The image is prebuilt, so there is no compile step on your machine.

bash
docker compose up -d

Open http://localhost:8000 and log in with the ADMIN_USER and ADMIN_PASS you set. The dashboard is the first screen, and invoice creation is reachable from there. Create one invoice, then use the share link the app generates. That link is what your client opens, with no account and no login prompt. If the page loads but saving an invoice fails, check ORIGIN first; it is the most common configuration mistake in a SvelteKit deployment behind a proxy.

Where Invio Stops Being the Right Tool

The README is explicit that Invio is small, and that has consequences. There is no mention of recurring invoices, dunning, or automated payment reminders. If you bill the same retainer every month to twenty clients, you will be creating invoices by hand or writing your own automation against the backend.

Payment collection is also thinner than the marketing line suggests. "Get paid" implies a payment path, but the README does not document a payment processor integration, and the .env.example lists no Stripe, PayPal, or bank keys. Treat the share link as a way to deliver an invoice, and verify separately how money actually reaches you. If your clients need a card checkout on the invoice page, confirm that exists before you migrate.

Operationally, the single SQLite file is both the strength and the weak point. It is trivial to back up and impossible to scale horizontally. Two containers writing to the same file over a network mount is a corruption risk, not a clustering strategy. And because authentication is a single admin account with a JWT session, there is no per-user audit trail. SESSION_TTL_SECONDS defaults to 3600 and accepts values between 300 and 43200, so a long session on a shared browser is a real exposure. COOKIE_SECURE defaults to true; the example says to set it false only for local HTTP development, and leaving it false in production is a mistake.

Invio Compared with Invoice Ninja and Crater

The closest alternatives in the self-hosted invoicing space are Invoice Ninja and Crater. The difference is architectural intent rather than feature count.

Invoice Ninja is a full business application. It carries a large Laravel codebase, a MySQL or MariaDB database, client portals with logins, recurring billing, expense tracking, and a long list of payment gateway integrations. It is the right answer when invoicing is one module in a broader operations system and you are willing to run a database server and a queue.

Crater takes a middle position: a Laravel and Vue application with a proper relational database and a broader feature set than Invio, but less surface than Invoice Ninja.

Invio's approach is the opposite of both. One container, one SQLite file, no client accounts, no documented plugin system. The comparison is not which one has more features; it is whether you want to administer a database and a queue to send invoices. If you do not, and you accept the missing features above, Invio is the smaller commitment. If you need recurring billing or gateway integrations today, you will be adding them yourself or choosing a larger project.

Licence, Maintenance, and Upgrade Cost

Invio is released under the Unlicense. That is a public domain dedication rather than a permissive licence with conditions: there is no attribution requirement, no copyleft obligation, and no warranty. For a self-hosted internal tool this is about as unobstructed as licensing gets. The practical caveat is that public domain code comes with no support commitment from anyone, and if you fork it, you own the fork. This is a description of the licence text, not legal advice; read LICENSE yourself if the distinction matters to your organisation.

The repository is not archived, and the last push was on 2026-09-07. Releases are infrequent but real: v2.2.0 on 2026-08-18, v2.1.1 on 2026-06-08, and v2.0.2 on 2026-05-20. The gaps between them are measured in months, so plan upgrades rather than expecting a continuous stream of patches.

Upgrade cost is low by construction. The Compose file pins ghcr.io/kittendevv/invio:latest, so pulling the image and recreating the container is the whole procedure. Your state lives in the invio_data volume, not in the container. But note the tag: latest means an unattended pull can move you across a minor version. If you want controlled upgrades, pin a specific tag in docker-compose.yml instead of relying on latest. The README does not document a database migration or rollback procedure, so take a copy of invio.db before you upgrade.

Editorial conclusion

Adopt Invio if you want a self-hosted invoice tool with a small surface area and you are comfortable reading the wiki before you expose it to the internet. Skip it if you need accounting integrations, tax filing, or multi-currency reconciliation; the README describes none of those. Before you commit, open the Quick Start page in the wiki, confirm the required values in .env.example match your deployment, and check that the weasyprint package your host provides can render the invoice PDFs you need.

Frequently asked questions

What is Invio?

It is a self-hosted invoicing application written in TypeScript, described in its README as "Selfhosted invoicing without the bloat." You run it on your own hardware, create an invoice, and share a link with your client.

Who created Invio?

The README credits kittendevv and contributors, with a link to the repository's contributor graph and a Ko-fi page for support. The project is developed under the kittendevv GitHub account.

Is Invio legit?

It is an open source project under the Unlicense, published on GitHub with a live demo at demo.invio.dev and documentation in the repository wiki. Because you self-host it, your invoice data stays on your own hardware rather than on a vendor's servers.

Official sources

  1. kittendevv/Invio on GitHub
  2. License: Unlicense
  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/kittendevv-invio.svg)](https://hysenlabs.com/projects/kittendevv-invio)