Create invoices, get paid online, track expenses, and own your data — all from a single ~50 MB container. A self-hostable alternative to FreshBooks, Wave, Zoho Invoice & Invoice Ninja.
Live Demo · Inkvoice Cloud · Documentation · Website
Inkvoice is a lightweight, self-hosted invoicing dashboard for people who'd rather own their billing than rent it. Send professional invoices, get paid online, keep an eye on expenses, and hand clean numbers to your accountant — without per-seat pricing or data lock-in.
- 🗄️ Own your data — everything lives in a single SQLite file you control.
- 📦 One container, runs anywhere — Docker, Coolify, Dokploy; ~50–100 MB RAM.
- ⚡ Modern & fast — Bun + Hono + React, no heavyweight runtime.
- 🌍 Multi-currency, multi-user, multi-language out of the box.
- ☁️ Don't want to self-host? Use the managed Inkvoice Cloud and skip the ops.
📊 Real production usage on a Dokploy host — Inkvoice idles at ~1% CPU and 41.79 MiB RAM (of a 512 MiB cap). The whole app comfortably fits on the cheapest VPS tier.
Try it right now on the live demo — no signup required.
Invoicing
- Full lifecycle: draft → send → paid → void, plus one-click duplicate
- Line items, discounts and multiple tax rates with auto-calculation
- Polished PDF export (headless Chrome) with customizable Mustache templates
- Public shareable links with read receipts — see when a client opens an invoice
Quotes & recurring
- Quotes you can share and convert into invoices
- Recurring invoices with automated generation on a schedule
Get paid
- Online card payments via Stripe & PayPal
- Manual and partial payment tracking
Money & books
- Multi-currency with live exchange rates + base-currency consolidated reporting
- Expense tracking — billable expenses, receipts and categories
- Customer account statements (PDF per period)
- Reports — tax summary, A/R aging, revenue by customer & product, profit & loss, expenses by category, currency breakdown, and cash-flow forecast — every report exports to CSV
Platform
- Multi-user with role-based permissions and an activity log
- Built-in i18n (English, Turkish, Spanish, German & French — easy to add more)
- Dark mode, fully responsive
- Single Docker container, native SQLite, tiny footprint
| Invoices | Invoice detail |
![]() |
![]() |
| Reports (Profit & Loss) | Customers |
![]() |
![]() |
| Products & services | Dark mode |
![]() |
![]() |
docker compose up -dOpen http://localhost:3000 and log in with admin / changeme. Change the password from the user menu right away.
bun install
bun run dev # backend (:3000) + frontend (:5173) togetherbun run build # build the frontend
bun run start # serve API + static frontend on :3000Inkvoice ships as a single container — point any Docker host at the bundled Dockerfile, expose port 3000, and mount a volume on /app/data so the SQLite database survives redeploys.
- New resource → Public Repository → paste this repo's URL.
- Build pack: Dockerfile (the repo root
Dockerfile). - Port:
3000. - Persistent storage: add a volume on
/app/data— without it, every deploy wipes the database. - Environment: set at least
JWT_SECRET(≥ 32 chars),ADMIN_PASS, andCOOKIE_SECURE=true. - Domain: attach one and Coolify issues a Let's Encrypt cert; then set
ENABLE_HSTS=true. - Health check: point it at
/health.
Same shape as Coolify — create a Docker service from this repo, expose port 3000, mount a volume on /app/data, and set JWT_SECRET + ADMIN_PASS.
docker build -t inkvoice .
docker run -d \
--name inkvoice \
-p 3000:3000 \
-v inkvoice-data:/app/data \
-e JWT_SECRET="$(openssl rand -base64 48)" \
-e ADMIN_PASS="change-me-please" \
-e COOKIE_SECURE=true \
-e ENABLE_HSTS=true \
inkvoiceCopy .env.example to .env to bootstrap a local config. Most runtime knobs (currency, locale, invoice number pattern, email templates, etc.) live on the in-app Settings page — environment variables are reserved for deploy-time concerns (auth, ports, secrets).
| Variable | Required | Default | Description |
|---|---|---|---|
ADMIN_USER |
yes | admin |
Initial admin username (created on first boot if no users exist) |
ADMIN_PASS |
yes | changeme |
Initial admin password |
JWT_SECRET |
yes | (dev-only fallback) | JWT signing secret — must be ≥ 32 chars in production |
DATABASE_PATH |
no | ./data/invoice.db |
SQLite database file path |
PORT |
no | 3000 |
HTTP listen port |
HOST |
no | 0.0.0.0 |
Bind address |
SESSION_TTL |
no | 3600 |
JWT lifetime in seconds |
COOKIE_SECURE |
no | true |
Set to false for plain-HTTP development |
ENABLE_HSTS |
no | false |
Send HSTS header (set to true behind HTTPS) |
RATE_LIMIT_ENABLED |
no | true |
Enable login rate limiting |
RATE_LIMIT_MAX_ATTEMPTS |
no | 5 |
Max failed logins per window |
RATE_LIMIT_WINDOW |
no | 900 |
Rate-limit window in seconds |
ALLOWED_ORIGINS |
no | localhost:5173,3000 |
Comma-separated CORS allow-list |
CHROME_PATH |
no | (auto-detected) | Override Chrome/Chromium binary path for PDF rendering |
SMTP_HOST |
no | — | SMTP host. Set this group to enable invoice email sending |
SMTP_PORT |
no | 587 |
SMTP port |
SMTP_USER |
no | — | SMTP username |
SMTP_PASS |
no | — | SMTP password |
SMTP_FROM |
no | — | Sender address |
SMTP_SECURE |
no | false |
Use TLS (set true for port 465) |
STRIPE_SECRET_KEY |
no | — | Stripe secret key (sk_…) — enables Stripe online payments |
STRIPE_PUBLISHABLE_KEY |
no | — | Stripe publishable key (pk_…) |
STRIPE_WEBHOOK_SECRET |
no | — | Stripe webhook signing secret (whsec_…) |
PAYPAL_CLIENT_ID |
no | — | PayPal REST app client ID — enables PayPal online payments |
PAYPAL_SECRET |
no | — | PayPal REST app secret |
PAYPAL_WEBHOOK_ID |
no | — | PayPal webhook ID (signature verification) |
PAYPAL_ENV |
no | sandbox |
PayPal environment: sandbox or live |
DEMO_MODE |
no | false |
Periodically reset DB to seeded demo data (for public demo deploys) |
DEMO_RESET_INTERVAL |
no | 86400000 |
Demo reset interval in ms (default 24h) |
| Layer | Choice |
|---|---|
| Runtime | Bun |
| Backend | Hono + SQLite (bun:sqlite), Zod validation, JWT auth |
| Frontend | React 19 + Vite, Tailwind CSS + shadcn/ui |
| Headless Chrome + Mustache templates | |
| Packaging | Single Docker container serving API + static SPA |
- Architecture overview — components, data flow, where to add features.
- Template variables — every
{{token}}available in invoice/quote/email templates. - Contributing — setup, conventions, and PR checklist.
- Full docs: docs.inkvoice.app
PRs are welcome! Please read CONTRIBUTING.md for setup and conventions. Found a bug or have an idea? Open an issue.
The source code is MIT licensed.
The Inkvoice name and logos are trademarks and are not covered by the MIT license — see TRADEMARK.md for what's free to do and what needs a quick word. Running, forking, and "Inkvoice hosting" are all fine; hosting providers wanting an official listing are welcome to get in touch.





