Test coverage reporting: your CI uploads a coverage file, and it comments on the pull request with what the change covered and what it did not.
Build me coverage reporting that replaces Codecov: a comment on the pull request saying what the change covered, and a trend I can see. STACK - Node 20+ with Fastify - SQLite through better-sqlite3, WAL mode - Coverage files parsed from the formats tools already emit — lcov, Cobertura XML, Istanbul JSON, Go's own, JaCoCo - Caddy in front THE DATA MODEL - repos: id, name, provider, external_id, default_branch, token_hash, target_percent, threshold_percent, created_at - reports: id, repo_id, commit_sha, ref, pull_number, parent_sha, uploaded_at, flags_json, is_complete - file_coverage: id, report_id, path, lines_total, lines_covered, branches_total, branches_covered, functions_total, functions_covered - line_hits: report_id, path, line, hits — the big table, and the one that makes per-diff coverage possible - comparisons: id, base_report_id, head_report_id, computed_at, summary_json - comments: id, pull_number, external_comment_id, posted_at, updated_at — one comment per pull request, edited, never a new one per push - Every report kept. A coverage number without its history is a number nobody acts on UPLOADING - A small uploader script or binary called from CI: it finds the coverage file, parses it, and posts a compact payload - Authenticated with a per-repository token, and for public forks with an unauthenticated flow that is rate-limited and clearly marked - Several uploads per commit merged, flagged by suite — unit, integration, end-to-end — so a partial run does not look like a coverage collapse - A report is not complete until the expected number of flags has arrived or a timeout passes; comparing against an incomplete report is the classic source of a wrong scary number - Idempotent per commit and flag: a retried upload replaces rather than adds THE DIFF COVERAGE, WHICH IS THE ONLY NUMBER WORTH READING - Fetch the diff between base and head from the forge, or compute it from the two commits - For each added or modified line, look up its hit count in the head report - Report: lines added, lines covered, and the percentage. That is the number a reviewer should look at, and total project coverage is close to meaningless in a pull request - List the uncovered added lines by file, with a few lines of context, in the comment itself. A link to a dashboard is a link nobody follows - Handle a moved file, a renamed file, and a file with no coverage data at all — the last one is common and must say 'no data' rather than 'zero per cent' THE COMMENT - One comment per pull request, edited in place on every push. A new comment per push is the reason these tools get muted - It says: diff coverage, the change in project coverage, and the uncovered new lines. Three things, short enough to read without scrolling - A status check that passes or fails against the target and the threshold, with the threshold allowing a small drop so a refactor is not blocked by noise - Configurable to comment only when something is worse, which is the setting most teams eventually want HISTORY - Coverage per commit on the default branch, charted as inline SVG - Per file and per directory, so a decaying corner of the codebase is visible - Files with the most uncovered lines, ranked, which is the actual to-do list - A sunburst or a treemap only if it earns its place; the ranked list is more useful CONFIGURATION - A file in the repository: target, threshold, paths to ignore, flags and their expected count, and whether to comment on every push - Ignore rules that actually work: generated code, vendored code, migrations, and test files themselves - Validated by the same code that reads it, with a command to check it locally FORGE INTEGRATION - An app or a token with the minimum scopes: read the diff, write a comment, write a status - Webhook on pull request opened and synchronised, with signature verification and idempotency by delivery id - Rate limits respected with backoff OPERATIONS - .env: DATABASE_PATH, BASE_URL, FORGE_TOKEN, WEBHOOK_SECRET, SESSION_SECRET - Migrations on boot, each once - line_hits pruned on a schedule for old commits, keeping the summaries — this table is the bulk of the storage - Nightly backup off the machine, restore script - Health endpoint WHAT MATTERS MOST Diff coverage and the single edited comment. Build the line mapping between diff and report first and check it against a real pull request with a rename and a moved block in it. Project-wide percentage is easy and nearly useless; the coverage of the lines being reviewed is the whole product. Give me the repository, the uploader, migrations, .env.example, and a README with deploy steps behind Caddy and the CI snippet to add.
What you lose
- A pull-request comment showing coverage of the changed lines specifically, which is the only coverage number worth reading
- History across branches, so a trend is visible rather than a single number
- Support for every coverage format without you parsing any of them
If you would rather not build
- Coverlet or istanbul plus a diff parser
- Codecov free tier, for open-source projects
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $12/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
diff-cover
$0Computes coverage of the lines a diff touched, from standard report formats.
Bachmann1234/diff_coverfree · open source
lcov
$0The report format and tooling most runners already emit.
linux-test-project/lcovfree · open source
Why this verdict
our own opinion · changed only by a person
85/100
Verdict yes at 85. Intersecting the diff with the coverage report is about forty lines and produces the only coverage number that means anything.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Codecov
answered from the record above
Is Codecov free?
No — the plan we track is $12 a month. Pro at $12 per user per month billed monthly, cheaper annually; free for open-source projects.
Can you replace Codecov by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 85 out of 100, build time one session. Read what you lose before you decide.
How much does Codecov cost?
$12 a month on Pro — $144 a year. Recorded 10 Aug 2026.
What do you lose by replacing Codecov?
A pull-request comment showing coverage of the changed lines specifically, which is the only coverage number worth reading; History across branches, so a trend is visible rather than a single number; Support for every coverage format without you parsing any of them. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Codecov?
Yes: diff-cover, lcov. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

