• Start

Metrics reference

Access paths, label catalogue and the complete metric reference for SurrealDB Community and Enterprise, with a migration table from 3.0.

This page is the canonical reference for every metric emitted by SurrealDB. It covers how operators access them, the labels and naming rules that govern the surface, the full catalogue grouped by signal family, the public allowlist for anonymous scrapers, and the migration table from 3.0 names.

Available since: v3.1.0

The instruments listed below were introduced as part of the 3.1 observability overhaul. The Migration from 3.0 section at the bottom maps every legacy Prometheus name to its current replacement.

Metrics can be exposed in two complementary ways. Both pipelines can run simultaneously.

PropertyValue
TriggerSURREAL_METRICS_ENABLED=true (default)
TransportGET /metrics on the main HTTP port, content-type text/plain; version=0.0.4
AuthenticationRoot credentials gate the full surface. Anonymous scrapers receive the PUBLIC_METRICS allowlist only.
SurfaceEvery instrument the running build registers.

Disable the endpoint by setting SURREAL_METRICS_ENABLED=false — the route then returns 404.

PropertyValue
TriggerSURREAL_TELEMETRY_PROVIDER=otlp
TransportgRPC, default endpoint http://localhost:4317, push cadence from OTEL_METRIC_EXPORT_INTERVAL (milliseconds; default 60000), cumulative temporality
AuthenticationThe collector's responsibility. The exporter speaks gRPC and native-TLS but does not enforce client authentication.
SurfaceThe same instruments as /metrics, plus the OTel logs surface (audit and slow-query records, when their OTel export is enabled) and tracing spans.

Selectively disable parts of the OTLP pipeline:

  • SURREAL_TELEMETRY_DISABLE_METRICS=true — suppress the OTLP metrics reader, leaving logs and traces unaffected.

  • SURREAL_TELEMETRY_DISABLE_TRACING=true — suppress the OTLP trace exporter, leaving metrics and logs unaffected.

For the full environment variable reference, see Configuration.

OpenTelemetry instrument names use a dotted form (surrealdb.statement.duration). The Prometheus text exporter converts each instrument deterministically:

  • Counters get a _total suffix.

  • Histograms and counters with unit s get a _seconds suffix.

  • Histograms and counters with unit By get a _bytes suffix.

  • Up-down counters render as plain gauges with no suffix.

  • Attribute keys containing dots (http.request.method, http.route, rpc.method) are sanitised to underscore form at render time.

A few worked examples:

OpenTelemetry nameUnitPrometheus name
surrealdb.statement.durationssurrealdb_statement_duration_seconds
surrealdb.statement (counter)surrealdb_statement_total
surrealdb.http.request.sizeBysurrealdb_http_request_size_bytes_total
surrealdb.process.memoryBysurrealdb_process_memory_bytes
surrealdb.http.active_requests (up-down counter)surrealdb_http_active_requests

Every labelled family carries outcome plus the resolved tenant context (namespace, database, user) where applicable. Unresolved values render as the "-" sentinel; record-access principals render as the fixed <record> sentinel.

KeyBounded values
outcomesuccess, error, cancelled
statement_typeselect, update, create, … (closed AST set)
namespace / database / userFree-form strings up to a user-configured length. "-" when unresolved; <record> for record-access principals.
protocolwebsocket, http
auth_actionsignin, signup, authenticate, …
auth_scoperoot, namespace, database, record, none
http_request_methodget, post, put, delete, patch, head, options
http_routeMatched router pattern, bounded by the router definitions. "-" for unmatched.
http_response_status_codeStringified status (200, 400, …)
rpc_methodBounded by the RPC dispatch table.
error_classBounded; populated only when outcome != success.

The SurrealDS cluster family adds a small set of additional labels (peer, kind, message_type, path, phase, role, result, source, reason). See SurrealDS labels further down.

The catalogue is grouped by signal family. Each subsection lists the Prometheus name (the form an operator scrapes), the instrument type, the edition that exposes it, the labels it carries, and any notes.

Community
NameTypeLabelsNotes
surrealdb_build_infogaugebuild_versionAlways 1. The value carries no signal; the label is the static compile-time version.
surrealdb_process_uptime_secondsgaugeSeconds since process start.
surrealdb_process_memory_bytesgaugeResident set size of the process.
surrealdb_process_cpu_percentgaugeAggregate process CPU %. May exceed 100 on multi-core hosts.
target_infogaugeresource attributesEmitted by the OTel SDK from the process Resource. Carries service_edition.
otel_scope_infogaugescope attributesEmitted by the OTel SDK per instrumentation scope.

The cadence of the process snapshot can be tuned with SURREAL_PROCESS_METRICS_REFRESH_INTERVAL (seconds; default 5, floored at 1).

Community
NameTypeLabels
surrealdb_statement_totalcounterstatement_type, outcome, error_class, namespace, database, user
surrealdb_statement_duration_secondshistogramsame as above
surrealdb_statement_rows_totalcountersame as above. Recorded only when result_rows > 0.
Community
NameTypeLabels
surrealdb_query_totalcounteroutcome, error_class, namespace, database, user
surrealdb_query_duration_secondshistogramsame as above
Community
NameTypeLabels
surrealdb_transaction_totalcounterwrite, outcome, error_class, namespace, database, user
surrealdb_transaction_duration_secondshistogramsame as above
surrealdb_transaction_kv_ops_totalcounterop (get / scan / set / del / …)
surrealdb_transaction_keys_read_totalcounteroutcome
surrealdb_transaction_keys_written_totalcounteroutcome
surrealdb_transaction_key_bytes_read_totalcounteroutcome
surrealdb_transaction_value_bytes_read_totalcounteroutcome
surrealdb_transaction_key_bytes_written_totalcounteroutcome
surrealdb_transaction_value_bytes_written_totalcounteroutcome
surrealdb_transaction_conflicts_totalcounternamespace, database, user only. Doubles as the retry-pressure signal — alert on rate(...[5m]).
Community
NameTypeLabels
surrealdb_rpc_totalcounterrpc_method, outcome, error_class, namespace, database, user
surrealdb_rpc_duration_secondshistogramsame as above
Community
NameTypeLabels
surrealdb_auth_totalcounterauth_action, auth_scope, outcome, error_class, namespace, database, user
Community
NameTypeLabels
surrealdb_session_totalcountersession_action (connect / disconnect), protocol, service
surrealdb_session_activegaugeprotocol, service
surrealdb_session_duration_secondshistogramprotocol, service
Community
NameTypeLabels
surrealdb_network_received_bytes_totalcounterprotocol, namespace, database, user
surrealdb_network_sent_bytes_totalcountersame as above
Community
NameTypeLabels
surrealdb_http_request_totalcounterhttp_request_method, http_route, http_response_status_code, outcome, error_class, namespace, database, user
surrealdb_http_request_duration_secondshistogramsame as above
surrealdb_http_request_size_bytes_totalcountersame as above
surrealdb_http_response_size_bytes_totalcountersame as above
surrealdb_http_active_requestsgaugehttp_request_method, http_route (attribute-stripped to keep the gauge balanced)
Community
NameTypeLabels
surrealdb_live_query_activegauge
surrealdb_live_query_notifications_totalcounter
Community
NameTypeLabels
surrealdb_slow_query_totalcounterSame labels as surrealdb_statement_total. Increments when statement duration ≥ SURREAL_SLOW_QUERY_METRIC_THRESHOLD_MS (default 1000 ms; 0 disables the counter).

The slow-query counter is a Community-edition signal — it bumps for every statement that crosses the threshold. The Enterprise slow-query log pipeline produces full records on top of this counter.

Community
NameTypeLabels
surrealdb_graphql_operation_totalcounteroperation_type (query / mutation / subscription), outcome, error_class, namespace, database, user
surrealdb_graphql_operation_duration_secondshistogramsame as above
Community
NameTypeLabels
surrealdb_mcp_tool_invocation_totalcountertool, transport, outcome, error_class, namespace, database, user
surrealdb_mcp_tool_duration_secondshistogramsame as above
surrealdb_mcp_session_activegaugetransport
Community

Each enabled backend publishes a manifest of u64 values through the transaction layer. The server bridge registers each entry as an observable gauge under surrealdb.storage.<backend>.<metric>; Prometheus renders them as surrealdb_storage_<backend>_<metric>. The set is backend-specific (RocksDB, in-memory, SurrealKV) and may change between releases — the canonical list at runtime is whatever the running build exposes at /metrics.

Treat these metrics as operator-only — they leak backend-specific implementation detail (compaction stats, block cache hits, etc.) that is rarely meaningful outside the operator persona.

Enterprise

The SurrealDS cluster family is registered by the Enterprise composer when the runtime has at least one metrics reader configured. Every instrument is operator-only — the PUBLIC_METRICS allowlist excludes the family in its entirety.

NameTypeLabels
surrealdb_ds_network_bytes_sent_bytes_totalcounter (By)peer
surrealdb_ds_network_bytes_received_bytes_totalcounter (By)peer (omitted on reply-only variants)
surrealdb_ds_network_packets_sent_totalcounterpeer
surrealdb_ds_network_packets_received_totalcounterpeer (omitted on reply-only variants)
surrealdb_ds_network_send_errors_totalcounterpeer, kind
surrealdb_ds_messages_sent_totalcountermessage_type, peer
surrealdb_ds_messages_received_totalcountermessage_type, peer (omitted on reply-only variants)
surrealdb_ds_udp_reresolves_totalcounterreason
NameTypeLabels
surrealdb_ds_transactions_committed_totalcounter
surrealdb_ds_transactions_aborted_totalcounterreason
surrealdb_ds_occ_conflicts_totalcounter
surrealdb_ds_consensus_path_totalcounterpath
surrealdb_ds_consensus_fast_quorum_timeouts_totalcounter
surrealdb_ds_consensus_stale_view_aborts_totalcounter
surrealdb_ds_finalize_prepare_retries_totalcounter
surrealdb_ds_operation_timeouts_totalcounterphase
surrealdb_ds_prepare_results_totalcounterrole, result
surrealdb_ds_begin_replies_totalcounterrole, result (currently coordinator-side only)
surrealdb_ds_reads_served_totalcountersource
surrealdb_ds_reads_begin_backoffs_totalcounter
NameTypeLabels
surrealdb_ds_view_changes_totalcounteroutcome
surrealdb_ds_recovery_started_totalcounter
surrealdb_ds_recovery_completed_totalcounteroutcome
surrealdb_ds_recovery_transactions_applied_totalcounter
surrealdb_ds_prepare_probes_totalcounteroutcome
NameTypeLabels
surrealdb_ds_gc_supervisor_ticks_totalcounter
surrealdb_ds_gc_runs_totalcounterkind, outcome
surrealdb_ds_gc_records_collected_totalcounterkind
surrealdb_ds_gc_duration_secondshistogramkind, outcome

Populated only after the replica is wired in via the enterprise observer install hook.

NameTypeNotes
surrealdb_ds_replica_stategaugeEncoded Normal=0, ViewChange=1, Recovering=2, RecoveringCompleted=3.
surrealdb_ds_active_view_numbergaugeCurrent TAPIR view number.
surrealdb_ds_prepared_list_lengaugeLength of the prepared list.
surrealdb_ds_records_lengaugeLength of the records list.
surrealdb_ds_pending_finalises_lengaugeNumber of pending finalises.
surrealdb_ds_cluster_peers_unresolvedgaugeNumber of cluster peers currently unresolved.
KeyUsed onBounded values
peernetwork_*, messages_*Stringified NodeId (interned). Cardinality bounded by cluster size.
kindnetwork_send_errors, gc_runs, gc_records_collected, gc_duration_secondssend_failed, serialisation, channel_closed, unresolved, no_endpoint, write_failed, other (send errors); upgrade_tentative, gc_records, repair_tentative_consensus, gc_pending_finalises, gc_unlogged_inflight, gc_finalize_prepare_decisions, backup_recovery (GC).
message_typemessages_sent, messages_receivedTAPIR message variants (closed set).
pathconsensus_pathfast, slow
phaseoperation_timeoutspropose, finalize, broadcast, unlogged, recovery, inconsistent
roleprepare_results, begin_repliesreplica, coordinator
resultprepare_resultsok, abort, abstain, retry
resultbegin_replieseligible, anterior_prepared, higher_committed
outcomeview_changes, recovery_completed, prepare_probestriggered, completed, applied, retried, rebuild_failed (view changes); success, failure (recovery); committed, aborted, insufficient (probes).
sourcereads_servedlocal, remote_eligible, remote_higher_committed
reasontransactions_aborted, udp_reresolvesconflict, abstain, other (aborts); unresolved, send_failure, recovery_view_change (re-resolves).
Enterprise

Observable gauges registered when the audit log pipeline is enabled. The values are pulled at scrape time from atomic counters on the pipeline, so the cost is zero when nothing consumes the metric.

NameTypeNotes
surrealdb_audit_recordsgaugeCumulative count of records successfully enqueued (observer → queue).
surrealdb_audit_droppedgaugeCumulative count of records dropped (overflow or queue closed). Alert on any non-zero rate — every drop is a lost record.
surrealdb_audit_queue_depthgaugeRecords currently buffered between observer and worker. Sustained depth above ~50% of SURREAL_AUDIT_QUEUE_CAPACITY indicates a slow sink.
surrealdb_audit_appendedgaugeCumulative records the worker wrote to the sink. The gap to surrealdb_audit_records is queue depth plus append errors.
surrealdb_audit_append_errorsgaugeCumulative sink-write failures. Alert on any non-zero rate.

These are exposed as gauges, not counters — the values are pulled live from atomic counters on the pipeline. The Prometheus name therefore has no _total suffix even though the underlying values are monotonic.

Enterprise

The slow-query pipeline exposes the same shape as the audit pipeline under the surrealdb.slow_query scope:

NameTypeNotes
surrealdb_slow_query_recordsgaugeCumulative records enqueued.
surrealdb_slow_query_droppedgaugeCumulative records dropped. Alert on any non-zero rate.
surrealdb_slow_query_queue_depthgaugeCurrent queue depth.
surrealdb_slow_query_appendedgaugeCumulative records written to the sink.
surrealdb_slow_query_append_errorsgaugeCumulative sink-write failures. Alert on any non-zero rate.
Enterprise

The surrealdb.tenant meter scope is reserved for low-cardinality per-tenant rollups keyed on (namespace, database) only. No instruments are currently registered under it. Until rollups land, customer-tenant filtering must be done at a proxy by filtering the higher-cardinality labelled families on namespace / database.

Anonymous scrapers on /metrics see only the metrics on the public allowlist. Adding a metric to this list requires a security review. The six allowlisted metrics are:

  • surrealdb_build_info

  • surrealdb_process_uptime_seconds

  • surrealdb_process_memory_bytes

  • surrealdb_process_cpu_percent

  • target_info

  • otel_scope_info

Root credentials unlock the full surface for an authenticated scrape.

For cloud and multi-tenant deployments the recommendation is a three-tier whitelist:

  • Tier 1 — Always public. The allowlisted six above.

  • Tier 2 — Customer-visible (per-tenant, via proxy filter). A subset of labelled families exposed to customers showing their own usage. Every metric in this tier carries namespace and database labels and the cloud proxy MUST filter on those before responding to a customer request — there is no server-side mechanism today that restricts a labelled family to a single tenant. Strip the user label before exposing. Suggested subset: surrealdb_statement_*, surrealdb_transaction_total, surrealdb_transaction_duration_seconds, surrealdb_transaction_conflicts_total, surrealdb_query_*, surrealdb_http_request_total, surrealdb_network_received_bytes_total, surrealdb_network_sent_bytes_total, surrealdb_live_query_active, surrealdb_slow_query_total.

  • Tier 3 — Operator-only. Everything else: all surrealdb_ds_*, all pipeline self-metrics, surrealdb_rpc_* (full method dimension), surrealdb_auth_* (failure rates can be probed by an attacker), surrealdb_graphql_*, surrealdb_mcp_*, surrealdb_storage_*, surrealdb_http_active_requests (real-time concurrency snapshot), and the KV-layer surrealdb_transaction_* counters. Reach these over an internal sidecar or private network with root credentials.

FlagWhere it appliesMitigation
Tenant-identifyingnamespace, database, user on every labelled familyStrip or filter at the proxy before exposing to a customer. Anonymous scrapers cannot see any family carrying these labels because the families are absent from the public allowlist.
High-cardinalitypeer (DS, bounded by cluster size), http_route, rpc_methodFine internally. External exposure should be conditional on the route or method set already being public.
Workload inferenceAll process gauges (uptime, memory, CPU)Already on the allowlist, but in a single-tenant-per-pod deployment they correlate with tenant workload. Acceptable trade-off in most architectures.
PII riskAudit and slow-query records carry SQL when *_INCLUDE_SQL=true. The pipeline self-metrics are safe; the records themselves go to the file sink and (opt-in) OTLP logs, not to /metrics.Run the three-pass redactor; alert on *_append_errors.
Default-denyMulti-tenant deploymentsSet SURREAL_METRICS_ENABLED=false on customer-facing pods; serve scrapes from an internal sidecar bound to a non-tenant-visible interface.

A starter set for production:

  • rate(surrealdb_statement_total{outcome="error"}[5m]) rising sharply against a baseline — application or operator error spike.

  • rate(surrealdb_transaction_conflicts_total[5m]) rising — OCC pressure or retry storms.

  • rate(surrealdb_ds_consensus_fast_quorum_timeouts_total[5m]) > 0 — consensus is falling through to the slow path.

  • surrealdb_ds_replica_state != 0 for more than a few seconds — a replica is in view-change or recovery.

  • surrealdb_ds_cluster_peers_unresolved > 0 for more than a startup window — DNS or connectivity gap.

  • rate(surrealdb_audit_dropped[5m]) > 0 or rate(surrealdb_audit_append_errors[5m]) > 0 — audit records being lost.

  • surrealdb_audit_queue_depth sustained above ~50% of SURREAL_AUDIT_QUEUE_CAPACITY — sink is falling behind.

The 3.1 release renamed the metric surface to a consistent surrealdb.* namespace. Legacy Prometheus names that operators may still see in old dashboards, and their current replacements:

3.0 name3.1 replacement
surrealdb_statements_completed_totalsurrealdb_statement_total{outcome="success"}
surrealdb_statement_errors_totalsurrealdb_statement_total{outcome="error"}
surrealdb_queries_completed_totalsurrealdb_query_total{outcome="success"}
surrealdb_query_errors_totalsurrealdb_query_total{outcome="error"}
surrealdb_query_dim_duration_secondssurrealdb_query_duration_seconds
surrealdb_transactions_completed_totalsurrealdb_transaction_total{outcome="success"}
surrealdb_transaction_writes_totalsurrealdb_transaction_total{write="true",outcome="success"}
surrealdb_transaction_errors_totalsurrealdb_transaction_total{outcome="error"}
surrealdb_rpcs_completed_totalsurrealdb_rpc_total{outcome="success"}
surrealdb_rpc_errors_totalsurrealdb_rpc_total{outcome="error"}
surrealdb_auth_attempts_totalsurrealdb_auth_total
surrealdb_auth_failures_totalsurrealdb_auth_total{outcome!="success"}
surrealdb_http_requests_completed_totalsurrealdb_http_request_total{outcome="success"}
surrealdb_http_request_errors_totalsurrealdb_http_request_total{outcome="error"}
surrealdb_http_dim_active_requestssurrealdb_http_active_requests
surrealdb_network_dim_received_bytes_totalsurrealdb_network_received_bytes_total
surrealdb_network_dim_sent_bytes_totalsurrealdb_network_sent_bytes_total
http_server_request_duration_millisecondssurrealdb_http_request_duration_seconds
http_server_request_count_totalsurrealdb_http_request_total
http_server_active_requestssurrealdb_http_active_requests
rpc_server_request_duration_millisecondssurrealdb_rpc_duration_seconds
rpc_server_active_connectionssurrealdb_session_active{protocol="websocket"}

The otel_scope_name label also changes shape in 3.1: scopes are now signal-domain (surrealdb.statement, surrealdb.query, …) rather than edition-tier (surrealdb.community, surrealdb.enterprise). Dashboards that filtered by scope should switch to the metric name (which now carries the same information, since scopes mirror the family prefix) or to the service.edition resource attribute, which is the authoritative edition signal.

Was this page helpful?