Skip to content

CONCEPT Cited by 1 source

SQLCommenter query tagging

SQLCommenter is a Google-originated (google.github.io/sqlcommenter) open standard for appending key-value metadata to SQL queries as a SQL comment. The SQL is executed unchanged; the comment is inert from the database-engine perspective but observable to extensions, proxies, and log analyzers.

Syntax

A trailing (or inline) SQL comment with structured key-value pairs:

SELECT body, author_id, created_at FROM posts WHERE id = $1
/* category='viewPost', priority='critical' */

The application is in full control of the keys and values. Conventional keys the SQLCommenter spec defines include application, controller, action, framework, route, db_driver, traceparent. Teams routinely add their own (team, priority, category, user_id, feature_flag, etc.).

What it enables

Because the comment is an inert annotation on the SQL itself rather than a side-channel, any layer that inspects the SQL text can act on it:

  1. Query attribution — map each query back to the application code path that issued it (patterns/actor-tagged-query-observability, concepts/actor-tagged-error).
  2. Aggregate statistics broken down by tagconcepts/aggregate-tag-attribution / concepts/per-pattern-tag-cardinality at the observability tier.
  3. Workload-class resource enforcementpatterns/workload-class-resource-budget / patterns/shed-low-priority-under-load at the control tier. Budget rules key on tag values; queries get blocked or accepted by the tag they carry.
  4. Search / filter surface over captured query logs — tag:key:value filter syntax in the observability UI.
  5. Priority-based load sheddingpriority tiers encoded as a SQLCommenter tag at every call-site; the runtime control plane decides which class to shed.

Why comments, not side-channels

A few alternatives exist; SQLCommenter chose the comment-inside-SQL path deliberately:

  • Dedicated metadata headers — require client modifications, don't flow through connection pools cleanly, don't work with vanilla SQL clients.
  • Session variables (SET LOCAL) — one per session, not per query; also require round-trip and don't interleave with batched queries.
  • Stored-proc parameters — can't be added retroactively to existing query patterns.
  • Sampling / tracing context (OpenTelemetry) — orthogonal and compatible; SQLCommenter supports traceparent natively.

A SQL comment travels with the query through every layer (app ORM → connection pool → wire protocol → replica fanout → query log → extension) unchanged, with no engine-side coupling.

Canonical consumers

  • PlanetScale Insights Postgres extension — parses SQLCommenter tags at the extension layer, emits them into the observability pipeline, indexes per-tag aggregate stats.
  • PlanetScale Traffic Control — the control-plane consumer. Budget rules match on tag values (priority='critical', action='analytics', etc.); over-budget queries are blocked.
  • Google Cloud SQL Insights — Google's own first-party consumer; the spec is effectively a Google-originated convention promoted to an open standard.

Auto-populated tags alongside application-populated tags

Insights augments application-authored SQLCommenter tags with three auto-populated ones set at the Postgres / extension layer (Source: ):

  • application_name — set by the Postgres driver.
  • username — the Postgres role that issued the query.
  • remote_address — the client IP.

Auto-tags are available even if the application never adds a single SQLCommenter tag, giving operators a baseline attribution surface before application-level tag discipline is deployed.

Gotchas

  • Connection pool stripping. Some ORMs / pools strip comments from SQL by default (to canonicalise for cache lookup). Has to be configured to preserve comments.
  • Query-plan cache key sensitivity. If the cache key includes comment bytes, each new tag value produces a plan-cache miss. Postgres's pg_stat_statements normalises over comments by default; mixed-extension setups may differ.
  • Log-line bloat. Every query in the log is now longer; downstream log-analysis pipelines must be cardinality- aware (concepts/per-pattern-tag-cardinality, patterns/dynamic-cardinality-reduction-by-tag-collapse).
  • Arbitrary-string injection risk. User-controlled strings should never be interpolated into SQLCommenter tags — the same SQL-injection-hygiene rules apply as anywhere else in the SQL path.
  • Tag discipline is app-level work. The comment doesn't magically appear; every query path that matters must be tagged, which is a coordination problem across a codebase.

Seen in

  • canonical Go-language implementation companion. Josh Brown (2026-04-02) canonicalises SQLCommenter as the substrate for composable tag axes ([[concepts/composable- tag-axes]]) — five orthogonal axes (service / route / deployment / tier / workload) coexist on one tagged query via context.Context-threaded propagation, AND-composed at enforcement time by Traffic Control. The Go variant is the framework-less counterpart to the 2022 Rails ORM-middleware pattern: two application helpers (appendTags deterministic render + tagsFromContext copy-on-read) + a wrapper QueryContext method render tags at the database boundary. Canonical appendTags shape with sort.Strings(parts) for deterministic ordering (plan-cache stability) + url.Query Escape for value encoding. Also canonicalises the driver- side companion to application-level tags: application_name as a connection-string-level tag (patterns/dedicated-application-name-per-workload) set by the driver not the app — "ensures that it is always set for this service, no matter the query or connection string given."

  • earliest canonical wiki source for SQLCommenter in a Rails context. Mike Coutermarsh + Iheanyi Ekechukwu (2022-06-29) publish the how-to for enabling SQLCommenter- format tags on every ActiveRecord query via Rails 7's native query_log_tags framework feature + the PlanetScale-authored activerecord-sql_commenter gem that swaps the emission format from Rails's default key:value to SQLCommenter's key='value'. Establishes the exact byte-level format difference (Rails default vs SQLCommenter), the three-setting enable envelope (query_log_tags_enabled + query_log_tags = [...] + cache_query_log_tags), and the per-query annotate override as the complementary escape hatch. Earliest wiki disclosure of Insights's >1 sec tail-query capture threshold (narrower predecessor to the three-axis threshold canonicalised on 2022-09-27). Also the earliest instance in PlanetScale's own production-debugging voice of the tag-then-filter-in-Insights workflow — ~3 months before Hazen's canonical 2022-09-27 actor-tag post. Canonicalises ORM-layer query-comment tag propagation as a pattern across the pre-Rails-7 Marginalia → Rails 7 query_log_tags → SQLCommenter-format migration timeline.

  • sources/2026-04-21-planetscale-graceful-degradation-in-postgres — Canonical priority-classification instance: priority

  • category tags on every query drive a three-tier Traffic Control budget setup. First canonical wiki explanation of SQLCommenter as a named standalone primitive.
  • — First canonical wiki instance of SQLCommenter paired with Traffic Control. action=analytics tag drives the 1-concurrent-worker cap that protects the MVCC horizon.
  • — Extends SQLCommenter visibility from per-query notable- query stream to per-tag aggregate statistics; auto- populated tags canonicalised.
  • tag:key:value filter syntax in Insights search surface built on top of SQLCommenter tags.
Last updated · 542 distilled / 1,571 read