When a user updates a plugin through the AppStore, they currently see only the new version number — nothing about what changed. This page describes a light-touch convention that makes per-release notes available to tools (a future AppStore, Dependabot, npm's package page) and to humans browsing your repository.
The recommendation is deliberately tool-agnostic. Pick whichever of the established approaches below fits your workflow; what matters is the output shape, not how you produce it.
For each npm-published version of your plugin, aim to have:
1.4.2 ↔ git tag v1.4.2 or 1.4.2).CHANGELOG.md at the repo root following Keep a Changelog.Anything that produces that shape is fine. Downstream consumers read GitHub Releases via the public API, which is the same regardless of which tool produced the notes.
The simplest path: let GitHub generate the release body from merged PRs. This is the same logic as the Generate release notes button in the GitHub web UI, triggered from a workflow on tag push. No third-party changelog action required.
The example workflow uses this approach — tag push → create GitHub Release with auto-generated body → npm publish --provenance.
If you want to categorize entries by PR label (Features / Fixes / Other), add a .github/release.yml to your repo. GitHub reads it automatically.
release-drafter accumulates a draft release across PR merges, so you can review and edit notes before tagging. Useful if you want a human pass over the wording.
release-please, semantic-release, and changesets go further: they also drive version bumps from conventional commits or intent files, and maintain CHANGELOG.md automatically. More automation, more opinion — worth it for plugins that release frequently.
Whichever approach you pick, the quality of the generated notes depends on your commit messages and PR titles. The Signal K server contributing guide already covers this — the same conventions apply to plugin repositories.
When using GitHub's built-in generator (Approach 1), PR titles become the release-note lines. Write titles that make sense out of context: "fix AIS fallback when GPS source is missing" beats "fix bug".
Publish from a GitHub Actions job triggered by the same tag push that creates the release. Use npm provenance so consumers can verify the package was built from the linked commit:
permissions:
id-token: write # required for provenance
contents: read
steps:
- run: npm publish --provenance --access public
The example workflow shows the full shape, including a beta-tag branch for *-beta* versions.
If the publish step fails transiently after the GitHub Release was already created, re-run the failed publish job from the Actions UI. If that's not possible, cut a new patch tag (e.g. v1.4.3) rather than force-retagging — tags and releases should be immutable so downstream consumers of the GitHub Release can trust them.
Dependabot fetches the GitHub Release notes of each updated package and embeds them into its update PRs — so plugins that follow the contract above already benefit their downstream users. Dependabot is also useful for your plugin: it keeps the dependencies of your plugin (and the versions of the GitHub Actions your CI/release workflows use) up to date.
A minimal .github/dependabot.yml should cover two ecosystems:
npm — your plugin's runtime dependenciesgithub-actions — the versions of the actions your CI and release workflows useGroup non-breaking upgrades (minor + patch) into a single PR per ecosystem to cut down on noise; leave major-version bumps as their own PRs because they usually need a real look.
See examples/plugin-dependabot-example.yml for a copy-pasteable config with explanatory comments, and the Dependabot options reference for the full set of tunables.
package.json shape