# Browser-local by default, with Redis, Resend, Telegram and Drive already in the env template

> EasyInvoicePDF is an AGPL-3.0 Next.js invoice generator whose pitch is that invoices never leave your browser, and whose release notes are more interesting than its feature list: a nine month old bug that clipped the first letter off PDF labels, an email visibility toggle added after two releases, and a dependency floor that refuses anything younger than five days.

**VladSez/easy-invoice-pdf** — Free & Open-Source Invoice Generator - No Sign-Up, No Ads, Instant PDF Export, 100% In-Browser, and Fully Customizable Templates. ⭐ Star the repo if you like it

- Repository: https://github.com/VladSez/easy-invoice-pdf
- Website: https://easyinvoicepdf.com
- Stars: 1,101 · Forks: 107
- Language: TypeScript
- License: AGPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/vladsez-easy-invoice-pdf

## The app is 1.0.5 in package.json and 1.0.4 in the release list

The newest tag is v1.0.4, published 2026-09-04, and the manifest at the repository root says version 1.0.5. The manifest is also marked private, so nothing is published to npm and the version number only ever moves inside this repository. The release history is uneven: v1.0.0 on 2025-11-19, v1.0.1 on 2026-01-12, v1.0.2 on 2026-03-10, v1.0.3 on 2026-03-29, then a gap of more than five months to v1.0.4. The branch itself was pushed on 2026-10-02, so roughly four weeks of work sit after the newest tag with no release to point at. Anyone pinning a version is pinning v1.0.4 and therefore not pinning the version the source currently declares.

## The first release tag is named differently from the four after it

The links to full release notes are inconsistent. Versions 1.0.2, 1.0.3 and 1.0.4 point at tags of the form v1.0.2, v1.0.3 and v1.0.4. Version 1.0.1 points at `releases/tag/EasyInvoicePDF-1.0.1`, which is a different naming scheme with no v prefix and a product name in front. Nothing in the file says the tag was renamed, so the first release is still reachable only under its original name. That matters if you script anything against the releases list, since the first entry breaks the pattern that the next four follow. The release titles themselves are also uneven, with 1.0.4 carrying a full descriptive title and 1.0.2 carrying nothing but the number.

## Browser-only by default, with four hosted services already named in the config

The headline claim is that invoices are created and stored in your browser, and the feature list puts privacy first with the qualifier by default attached. The example environment file shows what the non-default path looks like. It has slots for Upstash Redis under the comment for subscription tokens, a Resend API key for email, a Telegram bot token and chat id for notifications, a Google Drive client email, private key and parent folder id, a Sentry DSN with separate server and client switches, and an Umami website id whose script loads only in production. There is also a plain `AUTH_TOKEN` marked as used for /api. None of these are required to produce a PDF in the browser, but all of them are laid out and named in the file a self-hoster is told to copy, which is a different picture from an application with no server dependencies.

## The env template ships a seller with a five digit SWIFT BIC

Every placeholder in that file has a value, not an empty assignment. The seller block is filled with SELLER_NAME set to Adam Smith, a London address, a VAT number of 12345, an account number of 12345 and a SWIFT BIC of 12345, and the buyer block with Random Company in Bristol, also on 12345, with INVOICE_NET_PRICE at 10000 and both email addresses pointing at mail.com. A BIC and an account number are exactly the fields a payment must not get wrong, so a copy of this file that is only half filled in is worse than an empty one, because the form renders a plausible looking invoice. The comment above the block is also misspelled, reading `# Sellet Info`. One route, `/api/generate-invoice`, is named in the file as the place these values are used, which means sending is a server side action driven by the seller's details held in configuration.

## PDF labels lost their first character for nine months

The most revealing entry in the v1.0.4 notes is a rendering bug: PDFs were missing the first character of labels, so the Spanish invoice term `Cobrar de` could come out as `obrar de`. In rare cases, on a text run, on a real invoice, which is the kind of defect that only surfaces when a user opens the file. It was fixed on 2026-09-04 and the first release carrying the feature set was v1.0.0 on 2025-11-19, so the bug shipped with version one and lasted across three subsequent releases. The same notes describe a structural improvement: the PDF is now generated once and the same document is shared by the desktop preview, the mobile viewer and the download button, replacing three separate renders of the same invoice.

## Email visibility in the PDF only became a choice in v1.0.3

Control over whether email addresses appear in the generated PDF arrived in v1.0.3 on 2026-03-29, alongside reworked seller and buyer forms with locked-state banners, a confirm dialog when discarding changes, and an out-of-date dates helper that flags stale fields and offers a button to update all of them at once. That this needed two minor releases says something about the original output. The same feature also ties into the localisation work from v1.0.1, where helper texts and the out-of-date banner were made to follow the invoice's own language and date format rather than the interface's. Tax handling went the same way: v1.0.1 made the label per invoice language and loosened VAT validation to accept numeric values and specific strings, so a plain VAT number that the earlier version rejected is now fine.

## The lint script type-checks with oxlint, and tsc only runs in type-check

Three scripts overlap and none of them is complete on its own. `lint` runs `next typegen` then `oxlint . --type-check --type-aware`, and `type-check:fast` runs the same linter with `--quiet`. The real compiler appears only in `type-check`, which is `next typegen && tsc --noEmit --diagnostics`. Formatting is `oxfmt .` with a `--check` mode, unused code is found by knip, and GitHub Actions are checked by `zizmor .` while `update-github-actions` runs `actions-up --min-age=7`. The dependency policy is the more interesting line:

```
"update-deps": "pnpm upgrade --interactive --latest -rLi --config.minimum-release-age=7200",
```

7200 minutes is five days, so an npm package has to have been published for that long before this project will take it. The Actions equivalent uses seven days instead of five, so the two supply-chain floors are deliberately set at different values.

## One script puts the dev server on a public URL, and e2e runs at two workers

Two conveniences describe the project's working style. The first is `expose-to-internet`, defined as `cloudflared tunnel --url http://localhost:3000`, which puts the local dev server on a public tunnel address in one command, alongside a named-tunnel variant. Useful for showing someone a change, and worth knowing about in a repository whose argument is that your invoice data stays on your machine. The second is `e2e:not-flaky`, defined as `pnpm e2e --workers=2`, which runs the Playwright suite with two workers instead of the default, alongside an `--update-snapshots` mode. The project names its own flaky-test remedy rather than leaving it to you, and the presence of `e2e/`, `playwright.config.ts` and `vitest.config.ts` at the root says the invoice templates are checked by both end to end and unit tests.

## Conclusion

It fits a freelancer or small business that wants a Stripe-looking invoice with a live preview, no account and no per-invoice cost, and that is content for the hosted version to render identically. It does not fit anyone whose data handling has to be provable from the repository alone, because the privacy claim is scoped to the default path and the shipped example configuration already names a hosted Redis, a transactional email provider, a chat bot and Google Drive. Before deploying your own instance, empty every value in that file including the seller bank details, set a real AUTH_TOKEN before any route under /api answers, and read the v1.0.4 notes to see which bug you would otherwise inherit from v1.0.0.

## FAQ

### Does EasyInvoicePDF store my invoices on a server?

The feature list says invoices are created and stored in your browser by default. The example environment file also defines slots for Upstash Redis, Resend, Telegram, Google Drive and an AUTH_TOKEN for /api, so a hosted path exists alongside the local one.

### What version of EasyInvoicePDF is current?

package.json declares 1.0.5 while the newest tag is v1.0.4 from 2026-09-04. The manifest is marked private, so no version is published to npm and 1.0.5 exists only in the repository.

### What changed in EasyInvoicePDF v1.0.4?

The PDF is generated once and shared by the preview, the mobile viewer and the download button, mobile tabs were redesigned, form dates now match the PDF, and a bug where PDFs lost the first character of labels, such as Cobrar de rendering as obrar de, was fixed.

### Can I control whether emails appear on an EasyInvoicePDF invoice?

Yes, since v1.0.3 on 2026-03-29, which added a seller and buyer email visibility toggle for the generated PDF along with a confirm dialog for discarding unsaved profile changes.

### How fresh can EasyInvoicePDF dependencies be?

The update-deps script passes a minimum release age of 7200 minutes, so an npm package must have been out five days before it is taken. GitHub Actions are held to a different floor of seven days through actions-up --min-age=7.

## Sources

- [License: AGPL-3.0](https://github.com/VladSez/easy-invoice-pdf/blob/main/LICENSE)
- [Project website](https://easyinvoicepdf.com)
- [README](https://github.com/VladSez/easy-invoice-pdf/blob/main/README.md)
- [Releases](https://github.com/VladSez/easy-invoice-pdf/releases)
- [VladSez/easy-invoice-pdf on GitHub](https://github.com/VladSez/easy-invoice-pdf)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vladsez-easy-invoice-pdf
