VictoriaMetricsStore — VictoriaMetrics time-series database

Read this page in the documentation

VictoriaMetricsStore — VictoriaMetrics time-series database Overview VictoriaMetrics is a fast, cost-effective time-series database. Crucially it is API-compatible with Prometheus: it exposes the same /api/v1/query and /api/v1/queryrange PromQL endpoints (plus MetricsQL extensions), so PromQL queries written against Prometheus work unchanged. Unlike Prometheus, VictoriaMetrics also accepts client-side writes — it can ingest data pushed to it in several line formats, including the Prometheus text exposition format via /api/v1/import/prometheus. There is no SQL-shaped query surface, no row-level UPDATE/DELETE, and no identifier escaping, so this engine does not fit the SQL Dialect interface. VictoriaMetricsStore implements the minimal NoSqlStore marker interface (src/nosql/store.ts) — connection lifecycle plus a getClient() escape hatch — and exposes the Prometheus-compatible read API plus VictoriaMetrics's write API. Identity: Property | Value | --------- | ------------------- | name | 'victoriametrics' | library | 'fetch' | No npm driver — HTTP over fetch VictoriaMetrics has no single canonical npm client; it is an HTTP/JSON (and text-ingest) API. Rather than depend on any package, this store talks to it with the global fetch — hence library is 'fetch', not the name of a driver package. There is nothing to lazy-require(): when no client is injected, a tiny internal fetch-based client (built by createFetchClient(baseURL, headers)) is constructed at connect time. Endpoints wrapped: Read (Prometheus-compatible, under /api/v1): instantQuery → GET /api/v1/query, rangeQuery → GET /api/v1/queryrange. These return the parsed data field of the response envelope. Write (VictoriaMetrics-specific): importPrometheus → POST /api/v1/import/prometheus; write builds one Prometheus-exposition line and POSTs it via importPrometheus. Injected client VictoriaMetricsStoreOptions.client accepts a pre-built HTTP client (typed as VictoriaMetricsHttpClient). When provided it is used verbatim and baseURL is ignored; otherwise the internal fetch-based client is built against baseURL. This is how the test suite injects a mock (no network) and how callers route requests through a custom transport. Connection Build a store from connection options and call connect(): Option | Type | Purpose | --------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------ | baseURL | string | Base URL of the VictoriaMetrics server. Defaults to http://localhost:8428 (DEFAULTVICTORIAMETRICSBASEURL).| client | VictoriaMetricsHttpClient | Optional pre-built HTTP client. When set, used verbatim and baseURL is ignored. | headers | Record<string, string> | Extra HTTP headers sent with every internal-client request. | Injected-client form Methods Read methods issue a GET and return body?.data; write methods POST a text body. Failures are wrapped in a DatabaseError (preserving the original error, e.g. VictoriaMetrics instantQuery failed: ...); using any method before connect() (or after disconnect()) throws a ConnectionError. Lifecycle Method | Signature | Behavior | ------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | connect | connect(): Promise<void> | Uses an injected client if provided, otherwise builds an internal fetch-based client against baseURL. Idempotent when already connected. Does not open a socket or make a request. | disconnect | disconnect(): Promise<void> | Drops the client reference (stateless HTTP — no socket to close). | isConnected| isConnected(): boolean | true only when connected and a client is present. | getClient | getClient(): VictoriaMetricsHttpClient | Returns the underlying (internal or injected) HTTP client. Throws ConnectionError if not connected. | Read API (Prometheus-compatible) Method | Signature | Endpoint | Behavior | -------------- | -------------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------ | instantQuery | instantQuery(promql: string, time?: string \| number): Promise<any>| GET /api/v1/query | Runs a PromQL/MetricsQL instant query (identical to the Prometheus endpoint). time is stringified when provided. Returns the data payload. | rangeQuery | rangeQuery(promql: string, options: RangeQueryOptions): Promise<any>| GET /api/v1/queryrange | Runs a PromQL/MetricsQL range query. Returns the data payload. | Write API (VictoriaMetrics-specific) Method | Signature | Endpoint | Behavior | ------------------ | -------------------------------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------- | importPrometheus | importPrometheus(lines: string \| string[]): Promise<any> | POST /api/v1/import/prometheus | Imports raw data in Prometheus text-exposition format. A single newline-delimited string is sent as-is; an array is joined with newlines. Sent with content type text/plain. | write | write(metric: string, value: number, timestamp?: number, labels?: Record<string, string>): Promise<any> | POST /api/v1/import/prometheus (via importPrometheus) | Writes a single sample by building one Prometheus-exposition line and importing it. | RangeQueryOptions Exposition-line helper The module also exports buildPrometheusLine(metric, value, timestamp?, labels?), which builds a single line of the form metric{label="value",...} value [timestampms]. Label values are escaped per the exposition format (\, ", newline). write() uses this internally. Example Verification status Unit / mock-verified only. The tests in tests/nosql/victoriametrics.test.ts are fully mock-driven: an in-memory mock HTTP client is injected via VictoriaMetricsStoreOptions.client; it records every GET (path + params) and POST (path + body + content-type) and returns canned responses. There is no network in the test run — the internal fetch-based client is never exercised against a live server. What this proves: Read methods GET the correct path with the expected params (instantQuery sends { query, time }, omitting/stringifying time; rangeQuery sends stringified { query, start, end, step }) and return the unwrapped data field. importPrometheus POSTs to /api/v1/import/prometheus with content type text/plain, sending a string as-is and joining an array of lines with newlines. write builds the correct exposition line (with and without timestamp/labels) and POSTs it. buildPrometheusLine formats metric/labels/value/timestamp and escapes quotes and backslashes in label values. Lifecycle: not connected before connect(), idempotent double-connect, clean disconnect, getClient() returning the injected client, and ConnectionError when querying or writing before connect(). Error handling: GET and POST failures both wrapped in DatabaseError. What this does not prove: live execution against a real VictoriaMetrics server, nor the internal createFetchClient transport (URL building, header forwarding, HTTP status handling) end-to-end over the wire. Related reading All data stores — the full catalogue, grouped by purpose Database types — where this sits among the 22 categories