Skip to content

Choosing a storage backend

Every Gutternote comment has two halves:

  • The anchor — which page, which element, where on it, and whether it’s resolved.
  • The body — the prose someone wrote, who wrote it, and any attachments.

Anchors are always stored by Gutternote. That isn’t a policy position, it’s what makes the product usable: rendering forty pins on page load has to be one indexed query, not forty round trips to a rate-limited third party. Anchors are coordinates and status flags, not content.

Bodies are yours to place.

The three backends

Gutternote Postgres — the default

Everything in our database. Full feature set, fastest reads, simplest operationally. Choose this unless you have a specific reason not to.

Your GitHub repo

Bodies become issue comments in a repo you own, via a GitHub App. Gutternote keeps the anchor and the issue number, and nothing else.

Good when your objection is “comment text must not sit in a vendor database” and your commenters all have repo access anyway.

Know the trade-offs before you pick it:

  • No attachments. GitHub has no supported API for programmatic uploads.
  • Everything is attributed to the app. GitHub shows gutternote[bot] as the author; the real name is carried in the comment body and rendered by the widget.
  • Reads are rate limited — roughly 5k requests/hour per installation — so thread bodies are fetched on open rather than on page load.
  • Threads can’t be truly deleted. GitHub’s API can’t delete an issue. Gutternote closes it; hard deletion has to happen in GitHub. If you have a data-deletion commitment, it must carve this out.

Your own endpoint

Bodies POST to an HTTPS endpoint you run, signed with HMAC-SHA256. Nothing but anchors touches Gutternote infrastructure, and unlike the GitHub backend you keep the full feature set — attachments, edits and guest authors all work if you implement them.

See the external store contract.

Or self-host the lot

If the real requirement is “none of this runs on your infrastructure”, the cleanest answer usually isn’t a storage backend — it’s running Gutternote yourself. One Go binary and a Postgres URL, in your VPC, with no product compromises at all.

Capabilities are advertised, not assumed

The widget calls /v1/config before rendering and reads the project’s capabilities, so it hides affordances the backend can’t honour rather than failing on submit:

{
"backend": "github",
"capabilities": {
"attachments": false,
"edit": true,
"delete": true,
"guestAuthors": false,
"lowLatencyReads": false
}
}