Open-source invoicing, expenses and bookkeeping for freelancers and small businesses. Self-hosted with Docker.
TypeScript
1
1 commits
updated Oct 3, 2026
Flexible bookkeeping, your way.
Open-source invoicing, time tracking and bookkeeping for freelancers and small businesses.
Self-hosted with one Docker command. Works in 40+ countries.

Most invoicing tools are built for one country and rent your own data back to you. Zedgerr runs on your own server, keeps everything in a single SQLite file you can back up, and adapts to the tax rules of the country you work in: VAT, GST, HST, sales tax or none at all.
Get paid
Know where you stand
Track everything in one place
Built to be used every day
![]() | ![]() |
| Dark mode | Invoices |
![]() | ![]() |
| Setup wizard with country presets | Guided product tour |
![]() | ![]() |
| Command palette | Country & tax settings |
![]() | ![]() |
| Two-factor authentication | Sign in |
Pick your country during setup and Zedgerr fills in the tax name, standard and reduced rates, currency, distance unit and the right labels for your registration and tax numbers. Everything stays editable.
| Region | Included |
|---|---|
| European Union | All 27 member states, with current 2026 VAT rates and reverse charge for cross-border B2B work |
| Europe (other) | United Kingdom, Switzerland, Norway |
| Americas | United States (sales tax, off by default for services), Canada (GST, HST or GST + PST per province), Mexico, Brazil |
| Asia-Pacific | Australia (GST + ABN), New Zealand, Singapore, Japan, India (GSTIN) |
| Africa and Middle East | South Africa, United Arab Emirates |
Your country isn't listed? Choose Other country and set your own tax name and rate.
Zedgerr helps you keep your books and prepare your figures. It is not tax advice; check your return with your tax authority or an accountant before filing.
git clone https://github.com/vMawk/zedgerr.git
cd zedgerr
docker compose up -d
Open http://localhost:3000. The first account you create becomes the administrator, and the setup wizard guides you through the rest.
docker build -t zedgerr .
docker run -d --name zedgerr -p 3000:3000 \
-e JWT_SECRET="$(openssl rand -hex 32)" \
-v zedgerr_data:/app/data \
zedgerr
Requires Node.js 22 or later.
npm ci
npm run build && npm run build:server
JWT_SECRET="$(openssl rand -hex 32)" NODE_ENV=production node dist-server/server/index.js
| Variable | Default | Description |
|---|---|---|
JWT_SECRET | required in production | Random string of at least 32 characters. Generate one with openssl rand -hex 32. |
PORT | 3000 | Port the server listens on. |
DATA_DIR | ./data | Folder for the SQLite database and uploaded files. |
ALLOW_REGISTRATION | false | true lets anyone create an account. The first account can always be created. Invite others from Settings → Team. |
TRUST_PROXY | false | Set to true behind nginx, Caddy or Traefik so rate limiting sees the real client IP. |
CORS_ORIGIN | Comma-separated origins, only needed when another domain calls the API directly. | |
OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL | Optional OpenAI-compatible endpoint for the "Improve with AI" button on time entries. |
HTTPS: put Zedgerr behind a reverse proxy that terminates TLS, and set TRUST_PROXY=true.
Backups: use Settings → Data → Backup to download an AES-256-GCM encrypted backup (.zdbk file). You choose the password; it never leaves your server. Restore from the same tab.
Updates: pull the new version and rebuild. Database migrations run automatically on start-up.
Health check: GET /healthz returns {"status":"ok"} when the server and database are up.
Remote access: Cloudflare Tunnel is supported — no port forwarding or certificates needed. Set TRUST_PROXY=true when using it.
There is no email-based reset, because a self-hosted install has no mail server configured by default. An administrator can set a new password from the server:
# Docker
docker compose exec app node dist-server/server/reset-password.js user@example.com 'new-password'
# Node.js
npm run reset-password -- user@example.com 'new-password'
Add --disable-2fa if the user also lost their authenticator app and recovery codes.
JWT_SECRETFound a vulnerability? Please report it privately to the maintainer instead of opening a public issue.
npm install
npm run dev
This starts the API on port 3000 (with auto-reload) and the Vite dev server on http://localhost:8080. A DEV button in the bottom-left corner lets you rerun the setup wizard or the product tour.
| Command | Purpose |
|---|---|
npm run dev | API and frontend with hot reload |
npm run build | Production build of the frontend |
npm run build:server | Compile the API and server to dist-server/ |
npm run lint | ESLint |
npm test | Unit tests (Vitest) |
api/ Hono API: routes, auth, two-factor, types
server/ Node.js entry point, SQLite and file storage adapters, admin scripts
migrations/ SQL migrations, applied in order on start-up
src/ React app (Vite, Tailwind, shadcn/ui)
pages/ One file per screen
components/ Layout, onboarding, command palette, settings
lib/ API client, tax presets, PDF generation
React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, Framer Motion, TanStack Query and Recharts on the frontend; Hono, better-sqlite3 and Node.js 22 on the server; jsPDF for invoices.
Issues and pull requests are welcome. For larger changes, open an issue first to discuss the approach. New country presets are a great first contribution — see src/lib/tax-presets.ts.
Zedgerr is built with love and maintained in our spare time. If it saves you time and money, consider supporting us so we can keep improving it:
FSL-1.1-ALv2 © Mark van Viegen
TypeScript
99.0%
Open-source invoicing, expenses and bookkeeping for freelancers and small businesses. Self-hosted with Docker.
TypeScript
1
1 commits
updated Oct 3, 2026
Flexible bookkeeping, your way.
Open-source invoicing, time tracking and bookkeeping for freelancers and small businesses.
Self-hosted with one Docker command. Works in 40+ countries.

Most invoicing tools are built for one country and rent your own data back to you. Zedgerr runs on your own server, keeps everything in a single SQLite file you can back up, and adapts to the tax rules of the country you work in: VAT, GST, HST, sales tax or none at all.
Get paid
Know where you stand
Track everything in one place
Built to be used every day
![]() | ![]() |
| Dark mode | Invoices |
![]() | ![]() |
| Setup wizard with country presets | Guided product tour |
![]() | ![]() |
| Command palette | Country & tax settings |
![]() | ![]() |
| Two-factor authentication | Sign in |
Pick your country during setup and Zedgerr fills in the tax name, standard and reduced rates, currency, distance unit and the right labels for your registration and tax numbers. Everything stays editable.
| Region | Included |
|---|---|
| European Union | All 27 member states, with current 2026 VAT rates and reverse charge for cross-border B2B work |
| Europe (other) | United Kingdom, Switzerland, Norway |
| Americas | United States (sales tax, off by default for services), Canada (GST, HST or GST + PST per province), Mexico, Brazil |
| Asia-Pacific | Australia (GST + ABN), New Zealand, Singapore, Japan, India (GSTIN) |
| Africa and Middle East | South Africa, United Arab Emirates |
Your country isn't listed? Choose Other country and set your own tax name and rate.
Zedgerr helps you keep your books and prepare your figures. It is not tax advice; check your return with your tax authority or an accountant before filing.
git clone https://github.com/vMawk/zedgerr.git
cd zedgerr
docker compose up -d
Open http://localhost:3000. The first account you create becomes the administrator, and the setup wizard guides you through the rest.
docker build -t zedgerr .
docker run -d --name zedgerr -p 3000:3000 \
-e JWT_SECRET="$(openssl rand -hex 32)" \
-v zedgerr_data:/app/data \
zedgerr
Requires Node.js 22 or later.
npm ci
npm run build && npm run build:server
JWT_SECRET="$(openssl rand -hex 32)" NODE_ENV=production node dist-server/server/index.js
| Variable | Default | Description |
|---|---|---|
JWT_SECRET | required in production | Random string of at least 32 characters. Generate one with openssl rand -hex 32. |
PORT | 3000 | Port the server listens on. |
DATA_DIR | ./data | Folder for the SQLite database and uploaded files. |
ALLOW_REGISTRATION | false | true lets anyone create an account. The first account can always be created. Invite others from Settings → Team. |
TRUST_PROXY | false | Set to true behind nginx, Caddy or Traefik so rate limiting sees the real client IP. |
CORS_ORIGIN | Comma-separated origins, only needed when another domain calls the API directly. | |
OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL | Optional OpenAI-compatible endpoint for the "Improve with AI" button on time entries. |
HTTPS: put Zedgerr behind a reverse proxy that terminates TLS, and set TRUST_PROXY=true.
Backups: use Settings → Data → Backup to download an AES-256-GCM encrypted backup (.zdbk file). You choose the password; it never leaves your server. Restore from the same tab.
Updates: pull the new version and rebuild. Database migrations run automatically on start-up.
Health check: GET /healthz returns {"status":"ok"} when the server and database are up.
Remote access: Cloudflare Tunnel is supported — no port forwarding or certificates needed. Set TRUST_PROXY=true when using it.
There is no email-based reset, because a self-hosted install has no mail server configured by default. An administrator can set a new password from the server:
# Docker
docker compose exec app node dist-server/server/reset-password.js user@example.com 'new-password'
# Node.js
npm run reset-password -- user@example.com 'new-password'
Add --disable-2fa if the user also lost their authenticator app and recovery codes.
JWT_SECRETFound a vulnerability? Please report it privately to the maintainer instead of opening a public issue.
npm install
npm run dev
This starts the API on port 3000 (with auto-reload) and the Vite dev server on http://localhost:8080. A DEV button in the bottom-left corner lets you rerun the setup wizard or the product tour.
| Command | Purpose |
|---|---|
npm run dev | API and frontend with hot reload |
npm run build | Production build of the frontend |
npm run build:server | Compile the API and server to dist-server/ |
npm run lint | ESLint |
npm test | Unit tests (Vitest) |
api/ Hono API: routes, auth, two-factor, types
server/ Node.js entry point, SQLite and file storage adapters, admin scripts
migrations/ SQL migrations, applied in order on start-up
src/ React app (Vite, Tailwind, shadcn/ui)
pages/ One file per screen
components/ Layout, onboarding, command palette, settings
lib/ API client, tax presets, PDF generation
React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, Framer Motion, TanStack Query and Recharts on the frontend; Hono, better-sqlite3 and Node.js 22 on the server; jsPDF for invoices.
Issues and pull requests are welcome. For larger changes, open an issue first to discuss the approach. New country presets are a great first contribution — see src/lib/tax-presets.ts.
Zedgerr is built with love and maintained in our spare time. If it saves you time and money, consider supporting us so we can keep improving it:
FSL-1.1-ALv2 © Mark van Viegen
TypeScript
99.0%