Introduction
Grafatui is a terminal user interface for Prometheus dashboards. It is designed for fast inspection, SSH sessions, local debugging, and environments where opening a browser-based Grafana instance is inconvenient.
Grafatui reads Prometheus directly and can import Grafana dashboard JSON files. It renders supported panels as terminal charts, tables, gauges, stats, and heatmaps while keeping the workflow keyboard-first.
When Grafatui Fits
Use Grafatui when you want:
- A lightweight Prometheus dashboard in your terminal.
- A familiar way to inspect exported Grafana dashboards.
- Fast startup and low resource usage.
- A dashboard that works well over SSH.
- SVG or PNG snapshots of the current TUI view.
Grafatui is not a Grafana server replacement. It does not manage users, alerts, annotations, dashboard editing, plugins, or browser-only visualizations.
Project Links
Installation
Homebrew
Install Grafatui with Homebrew on macOS or Linux:
brew install fedexist/grafatui/grafatui
Installer Script
Install the latest prebuilt release without requiring Rust:
bash -o pipefail -c 'curl --proto =https --tlsv1.2 -LsSf https://raw.githubusercontent.com/fedexist/grafatui/main/install.sh | bash'
With wget:
bash -o pipefail -c 'wget -O- https://raw.githubusercontent.com/fedexist/grafatui/main/install.sh | bash'
The script supports Linux and macOS on x86_64 and ARM64. It installs to
$HOME/.local/bin and never invokes sudo. Make sure that directory is on
your PATH.
Set GRAFATUI_INSTALL_DIR to choose another destination:
bash -o pipefail -c 'curl --proto =https --tlsv1.2 -LsSf https://raw.githubusercontent.com/fedexist/grafatui/main/install.sh | GRAFATUI_INSTALL_DIR=/custom/bin bash'
Set GRAFATUI_VERSION to install a specific release. The leading v is
optional:
bash -o pipefail -c 'curl --proto =https --tlsv1.2 -LsSf https://raw.githubusercontent.com/fedexist/grafatui/main/install.sh | GRAFATUI_VERSION=v0.1.11 bash'
Every release download is verified against its published SHA-256 checksum manifest. Installation stops if the manifest is unavailable or verification fails.
Reviewing downloaded scripts before running them is recommended:
curl --proto '=https' --tlsv1.2 -LsSf -o install.sh https://raw.githubusercontent.com/fedexist/grafatui/main/install.sh
less install.sh
bash install.sh
From Crates.io
Install the latest published release with Cargo:
cargo install grafatui
Grafatui currently requires Rust 1.88 or newer.
From Source
Clone the repository and install the local checkout:
git clone https://github.com/fedexist/grafatui.git
cd grafatui
cargo install --path .
For development, use cargo run instead:
cargo run -- --prometheus-url http://localhost:9090
Prebuilt Binaries
Prebuilt release assets are published on GitHub Releases for common Linux, macOS, and Windows targets.
Shell Completions
Grafatui can generate shell completions for Bash, Zsh, Fish, PowerShell, and Elvish.
# Bash
source <(grafatui completions bash)
# Zsh
source <(grafatui completions zsh)
# Fish
grafatui completions fish | source
Man Page
Generate a man page from the CLI definition:
grafatui man > grafatui.1
Quick Start
Connect to Prometheus
If Prometheus is already running locally:
grafatui --prometheus-url http://localhost:9090
Point Grafatui at another Prometheus server with the same option:
grafatui --prometheus-url http://prometheus.example.com:9090
Import a Grafana Dashboard
Grafatui imports either a Classic JSON dashboard or an exact
dashboard.grafana.app/v2 JSON resource that uses a GridLayout:
grafatui --prometheus-url http://localhost:9090 --grafana-json ./dashboard.json
For advanced V2 dashboards that use rows, tabs, auto-grid, repeat, conditional rendering, nested variables, or library panels, use the Classic export fallback: open Export as code → Advanced options, set Model to Classic, then download or copy the JSON. V1 Resource and Resource YAML files are unsupported. See Grafana Dashboard Import for the full format requirements.
Override dashboard variables with repeated --var options:
grafatui --grafana-json ./dash.json --var job=node --var instance=server-01
Run the Demo
The repository includes a Prometheus demo stack and sample dashboards:
git clone https://github.com/fedexist/grafatui.git
cd grafatui
cd examples/demo && docker-compose up -d && sleep 5 && cd ../..
cargo run -- --grafana-json examples/dashboards/prometheus_demo.json --prometheus-url http://localhost:19090
When finished:
cd examples/demo
docker-compose down -v
Useful First Keys
| Key | Action |
|---|---|
q | Quit |
r | Force refresh |
+ / - | Zoom out / in |
[ / ] | Pan left / right |
f / Enter | Fullscreen selected panel |
v | Inspect values |
/ | Search panels |
Configuration
Grafatui can be configured with CLI options, a TOML configuration file, or both. CLI options override values from the configuration file.
Common CLI Options
| Option | Description | Default |
|---|---|---|
--prometheus-url <URL> | Prometheus server URL | http://localhost:9090 |
--grafana-json <FILE> | Grafana dashboard JSON file | none |
--annotations-file <FILE> | Read-only external JSONL point-event file | none |
--annotations-command <PROGRAM> | Read-only executable annotation provider | none |
--annotations-command-arg <ARG> | Argument for --annotations-command; repeat to preserve order | none |
--annotations-command-timeout <DURATION> | Maximum command-provider runtime | 10s |
--validate | Check the Grafana dashboard import and exit without starting the TUI | false |
--strict | Make --validate fail when diagnostics contain warnings | false |
--format <FORMAT> | Output format for --validate: text or json | text |
--range <DURATION> | Time range window, such as 5m, 1h, or 24h | 5m |
--step <DURATION> | Query step resolution, such as 5s or 30s | 5s |
--var <KEY=VALUE> | Override a dashboard variable | none |
--theme <NAME> | UI theme | default |
--threshold-marker <MARKER> | Marker for threshold lines | dashed |
--autogrid-color <COLOR> | Color for automatic graph grid lines and labels | dark-gray |
--export-dir <DIR> | Directory for exports and recordings | ./grafatui-exports |
--export-format <FORMAT> | svg, png, or both | svg |
--record-max-frames <COUNT> | Maximum changed frames per recording | 300 |
--refresh-rate <MS> | Data fetch interval in milliseconds | 1000 |
--config <FILE> | Configuration file path | none |
Run the full help output with:
grafatui --help
Configuration File
Create grafatui.toml in ~/.config/grafatui/, or pass a custom path with --config.
prometheus_url = "http://localhost:9090"
refresh_rate = 1000
time_range = "1h"
step = "5s"
theme = "dracula"
threshold_marker = "dashed"
export_dir = "./grafatui-exports"
export_format = "svg"
record_max_frames = 300
autogrid = true
autogrid_color = "dark-gray"
grafana_json = "~/.config/grafatui/my-dashboard.json"
annotations_file = "./events.jsonl"
[vars]
job = "node"
instance = "server-01"
External Annotation Sources
Select one read-only annotation source: annotations_file or the nested
[annotations_command] table. The two TOML forms conflict. The
--annotations-file CLI flag conflicts with every command-source CLI flag;
CLI source selection still replaces the complete TOML annotation source.
[annotations_command]
program = "./target/debug/examples/git_annotation_provider"
args = ["."]
timeout = "10s"
program is required; args defaults to an empty list and timeout defaults
to 10s. The matching CLI source is:
grafatui \
--annotations-command ./target/debug/examples/git_annotation_provider \
--annotations-command-arg=. \
--annotations-command-timeout 10s
--annotations-command-arg and --annotations-command-timeout require
--annotations-command; repeat the argument flag to retain argument order.
--annotations-file and --annotations-command cannot be combined. A CLI file
or command has whole-source precedence over TOML: it replaces the configured
file or complete command configuration rather than merging individual fields.
Themes
Built-in themes include:
defaultdraculamonokaisolarized-darksolarized-lightgruvboxtokyo-nightcatppuccin
Use a theme from the CLI:
grafatui --theme tokyo-night
External Annotations
Grafatui can overlay read-only, external point events from exactly one source:
a JSONL file or a command provider. It never edits or writes either source.
External annotations are deliberately separate from Grafana dashboard
annotations: Grafatui does not implement Grafana annotation queries, APIs,
annotations, or annotations.list.
Enable Annotations
Select exactly one source. For a file source, pass the path on the command line:
grafatui \
--grafana-json ./dashboard.json \
--annotations-file ./events.jsonl
Or configure the file source in TOML:
annotations_file = "./events.jsonl"
For a command source, configure an executable that accepts the request protocol below. The command receives no shell interpolation:
[annotations_command]
program = "./target/debug/examples/git_annotation_provider"
args = ["."]
timeout = "10s"
Or select it from the command line:
grafatui \
--grafana-json ./dashboard.json \
--annotations-command ./target/debug/examples/git_annotation_provider \
--annotations-command-arg=.
File and command sources are mutually exclusive. A TOML configuration that sets both is rejected even if the CLI selects a source. A CLI file or command replaces the complete TOML annotation source; it never mixes a CLI program, arguments, or timeout with TOML values. Sources are opt-in and read-only; Grafatui does not create, edit, or otherwise write them.
Command Provider Protocol
Grafatui writes exactly one version-1 request line to the command’s standard input, then closes stdin. The request defines the complete refresh window:
{"version":1,"range":{"from":"2026-08-12T10:00:00Z","to":"2026-08-12T10:05:00Z"}}
range.from and range.to are inclusive UTC RFC 3339 bounds. Grafatui
defensively applies its visible-range filtering to the events returned.
The provider writes zero or more existing JSONL events to stdout and diagnostics
to stderr. Exit 0 with valid bounded JSONL replaces the complete annotation
snapshot; an empty successful stdout clears it. A spawn failure, timeout,
nonzero exit, invalid UTF-8 or JSONL, or oversized stdout keeps the last valid
snapshot and shows a warning.
The default timeout is 10 seconds. Grafatui accepts at most 10 MiB of stdout and captures at most 64 KiB of stderr. Providers inherit Grafatui’s current directory and environment. Put credentials in that environment or use standard credential tooling; never place secrets in dashboard JSON or command arguments.
The included Git provider is a practical starting point:
cargo build --example git_annotation_provider
printf '%s\n' '{"version":1,"range":{"from":"2026-08-12T10:00:00Z","to":"2026-08-12T10:05:00Z"}}' \
| ./target/debug/examples/git_annotation_provider .
JSONL Event Format and Targeting
The file contains one JSON object per line. Blank lines are ignored. Each event
requires time to be an RFC3339 string with an explicit timezone or offset
(numeric timestamps are rejected) and non-empty text. tags is an optional
array of non-empty strings.
{"time":"2026-07-23T14:30:00Z","text":"Maintenance window","tags":["maintenance"]}
{"time":"2026-07-23T14:30:00Z","text":"Deployed v2.4","tags":["deploy","production"],"panel_titles":["HTTP Request Rate by Status Code"]}
Omit panel_titles to target all eligible graph and timeseries panels, as in
the first event. When panel_titles is present, it must contain one or more
non-blank titles and each title is matched exactly and case-sensitively against
eligible graph/timeseries panel titles. null, an empty array, and blank
titles are validation errors.
If a title occurs on multiple eligible panels, the event fans out to all of them and Grafatui shows one warning for that duplicate title. A title that is missing, or exists only on a non-graph panel, shows one warning and renders no marker for that title. These titles are Grafatui routing labels, not Grafana panel IDs.
Events are ordered by timestamp. Unknown JSON fields are ignored. Times with fractional seconds are accepted, and the full fractional timestamp is used when projecting an event onto the graph even when the space-limited inline timestamp display shows less precision.
Target, Filter, Inspect, and Reload
This walkthrough uses current UTC timestamps so both events fall in the visible
15-minute range. It uses only POSIX shell tools; no jq is required.
First, start the bundled Prometheus demo stack from the repository root:
cd examples/demo && docker-compose up -d && sleep 5 && cd ../..
Then create the annotation file and run Grafatui:
annotation_demo_file=/tmp/grafatui-annotations-demo.jsonl
annotation_demo_time="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
printf '{"time":"%s","text":"Maintenance window","tags":["maintenance"]}\n' \
"$annotation_demo_time" > "$annotation_demo_file"
printf '{"time":"%s","text":"API deployed","tags":["deploy","production"],"panel_titles":["HTTP Request Rate by Status Code"]}\n' \
"$annotation_demo_time" >> "$annotation_demo_file"
cargo run -- \
--grafana-json examples/dashboards/prometheus_demo.json \
--prometheus-url http://localhost:19090 \
--range 15m \
--annotations-file "$annotation_demo_file"
Maintenance window appears on every graph/timeseries panel. API deployed
appears only on HTTP Request Rate by Status Code. Press t, select deploy
with Space, and press Enter; only the targeted deployment remains. Press
v, move the cursor to the marker, and press Enter; the selected panel’s
cluster list and selected-event detail pane open.
While Grafatui is running, append an event in a second terminal:
annotation_demo_file=/tmp/grafatui-annotations-demo.jsonl
annotation_demo_time="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
printf '{"time":"%s","text":"Rollback started","tags":["rollback","production"],"panel_titles":["HTTP Request Rate by Status Code"]}\n' \
"$annotation_demo_time" >> "$annotation_demo_file"
The new event is loaded after the normal refresh; Grafatui does not need to
restart. With only deploy selected, Rollback started remains hidden. Press
t, then c, and press Enter to apply the cleared filter and reveal the
rollback marker. Alternatively, select rollback in the filter and apply it.
Tag Filter and Cluster Controls
Press t to open the global annotation tag filter. It is runtime-only: it is
not written to the JSONL source or configuration, and applies to every eligible
panel. Selected tags use exact, case-sensitive OR matching: an event remains
visible when it has any selected tag. With no selected tags, events with and
without tags remain visible. The catalogue keeps a selected tag with a zero
event count so it can be removed after a reload.
In the tag filter, use Up/Down or j/k to move, Space to toggle the
highlighted tag, c to clear the draft, Enter to apply it, or Esc to
cancel without changing the applied filter. In inspection mode, Enter opens
only the cluster actually rendered by the selected panel at the cursor. In the
cluster, use Up/Down or j/k to select an event, PgUp/PgDn to page,
and Enter or Esc to close. Mouse input is ignored while either annotation
modal is open.
Cluster contents are frozen when the cluster opens: a later reload can replace the live annotation snapshot without moving rows or changing the cluster’s event details.
Automatic Reload, Rendering, and Exports
Grafatui refreshes both source types during each normal refresh, including while markers are hidden. It checks a file source’s metadata and, when it changes, reads, parses, and validates the full candidate file before atomically replacing the snapshot. A zero-byte file is a valid update that clears all events. Command and Prometheus refreshes share the same time range, start together, and redraw together. Annotation loading is independent of Prometheus: annotation failures never fail startup or a Prometheus refresh.
Only graph and timeseries panels receive annotation markers. Press a to
toggle marker visibility. Events that project to the same terminal column are
shown as one counted marker: • for one event, decimal 2–9 for two through
nine events, and + for 10 or more. In inspection mode, moving the cursor onto
that column shows the cluster’s timestamp, text, and tags inline; multi-event
details report the exact cluster count.
Applied panel targeting and tag filtering affect the markers in SVG/PNG exports and changed-frame recordings. Active inline annotation details are exportable; the tag-filter and cluster modal chrome is not.
Errors and Last Valid Snapshot
If a file is missing, unreadable, or contains a malformed event, Grafatui keeps rendering the last valid snapshot and shows an annotation warning. Command provider failures follow the same rule. A bad update does not replace the previously loaded events, fail startup, or fail the Prometheus refresh.
CI/CD and Provider Integrations
CI workflow → durable deployment/release record → command provider query
→ normalized JSONL point events → Grafatui overlay
GitHub Actions is a useful concrete pattern: let a workflow record deployment, release, or workflow outcomes in an API, object store, database, or shared event log. A local provider receives Grafatui’s requested range and queries that system of record, then emits normalized JSONL point events. Useful tags include repository, workflow, environment, status, commit, and deployment.
Give the provider credentials through its environment or standard credential tooling, never dashboard JSON or command arguments. A shared JSONL file is a reasonable source only when the workflow and Grafatui genuinely share storage; do not commit an ever-growing event log to the application repository. Vendor-specific providers should normally live as user or community plugins. Built-in integrations remain demand-driven.
Current Limits and Roadmap
This feature supports one external file or command source, point events,
panel-title routing, and one global runtime-only tag filter. It has no stable
event IDs, no per-panel tag filters, no multiple sources, and no editing. It
does not add Grafana annotation-query/API compatibility. Range events, stable
event IDs, and per-panel tag filters remain deferred. --validate validates
Grafana dashboard imports only; it does not validate annotations.
Grafana Dashboard Import
Grafatui imports supported Grafana dashboard JSON files and renders supported panels in the terminal.
| Format | Status | Requirements |
|---|---|---|
| Classic JSON | ✅ Supported | Non-resource object with fields such as title, panels, and templating |
| V2 Resource JSON | 🔶 Partial | JSON only, exact apiVersion: dashboard.grafana.app/v2, and spec.layout.kind: GridLayout |
| V1 Resource JSON | ❌ Unsupported | The dashboard.grafana.app/v1 resource envelope is not accepted |
| Resource YAML | ❌ Unsupported | --grafana-json accepts JSON only |
The supported V2 subset maps inline Panel elements, Prometheus PanelQuery
queries, top-level variables, timeSettings.autoRefresh, supported field
configuration, and fixed-grid positions to the same Grafatui behavior as
Classic JSON.
V2 layouts other than GridLayout (including Rows, Tabs, and Auto-grid) are
fatal import errors. Repeated grid items are also rejected rather than silently
changing the dashboard.
Export From Grafana
- Open the dashboard in Grafana.
- In the toolbar, open Export and select Export as code.
- Expand Advanced options.
- Set Model to Classic.
- Download the file, or copy the JSON into a local
.jsonfile. - Run Grafatui with
--grafana-json.
grafatui --prometheus-url http://localhost:9090 --grafana-json ./node-exporter.json
Grafana 13 defaults to the V2 Resource model. Its fixed-grid JSON resources can be imported directly. For advanced V2 dashboards, use this Classic export path as the fallback. Grafana documents the available models and export controls in Export a dashboard as code.
Supported Panel Types
Grafatui currently supports:
graphtimeseriesstatgaugebargaugetableheatmap
Row panels are traversed so nested panels can be imported, but row headers and collapsed row behavior are not rendered.
Variables
Grafatui reads dashboard variables from templating.list and expands $var and ${var} in PromQL expressions.
Defaults come from the dashboard JSON. Override them from the CLI:
grafatui --grafana-json ./dash.json --var job=node --var instance=server-01
Prometheus query variables such as label_values(up, instance) and query_result(...) are resolved before panel queries run.
Import Diagnostics
Grafatui prints import warnings before starting the TUI when a dashboard uses
important Grafana features that are skipped or ignored. Diagnostics include
unsupported panel types, value mappings, reduce options, unresolved variables,
unsupported V2 datasources, and unsupported variable modifiers such as
${var:regex}. V2 diagnostics retain their spec.* source paths.
Run a non-interactive check with:
grafatui --validate --grafana-json ./dash.json
Warnings do not make validation fail. A dashboard that can be parsed and imported exits successfully even if diagnostics are printed.
Use --strict to make warnings fail validation, or --format json to emit a
machine-readable summary. Fatal V2 layout and repeat errors fail validation in
all modes; --strict additionally fails when import diagnostics are present:
grafatui --validate --strict --grafana-json ./dash.json
grafatui --validate --format json --grafana-json ./dash.json
Hidden Targets
Grafatui honors targets[].hide by skipping hidden targets during import.
Panels with a mix of hidden and visible targets render only the visible target
queries.
Query Modes
Grafatui honors targets[].instant from Grafana dashboard JSON. Targets marked
as instant use the Prometheus instant query endpoint, while range targets use
query_range.
If a target does not specify instant, Gauge, Bar Gauge, and Table panels
default to instant queries. Graph, Timeseries, Stat, and Heatmap panels default
to range queries.
Field Configuration
Grafatui applies selected fieldConfig.defaults values where they map cleanly
to terminal rendering:
minandmaxset explicit Graph y-axis bounds and Gauge limits.thresholdsrender graph threshold lines and drive dynamic coloring for Stat, Gauge, and Bar Gauge panels.unit,decimals, andnoValueaffect supported panel values, axes, legends, and exports.custom.axisGridShowcontrols per-panel graph guide lines.
Built-In PromQL Variables
Grafatui expands the following Grafana-style variables:
$__interval$__interval_ms$__range$__range_s$__range_ms$__rate_interval$__rate_interval_ms
Compatibility Details
See the Grafana compatibility matrix for field-by-field support details.
Exporting and Recording
Grafatui can export the current dashboard view as SVG, PNG, or both. It can also record changed dashboard states into a timestamped frame bundle.
Export a Snapshot
Press e to export the current visible dashboard.
Output files are written under --export-dir:
grafatui --export-dir ./grafatui-exports --export-format both
Supported formats:
svgpngboth
Record Changed Frames
Press Ctrl+E to start recording. Press Ctrl+E again, or quit with q, to finalize the bundle.
Grafatui records only changed rendered states:
grafatui-recording-<timestamp>/
frame-000001.svg
frame-000002.svg
manifest.json
If --export-format png or both is selected, matching PNG files are written too.
When external annotations are visible, their panel targeting and applied tag filter affect the markers written to SVG/PNG exports and changed-frame recordings. Any active inline annotation details remain exportable. Annotation modal chrome is omitted from exports and recordings, and draft-only tag-filter edits do not create recording frames; a frame can change after the filter is applied or cleared.
Recording Limits
Limit the number of changed frames in one recording:
grafatui --record-max-frames 300
When the frame cap is reached, Grafatui stops writing new frames and records completed_reason = "capped" when finalized.
Manifest
Each recording writes a manifest.json file with metadata for downstream tooling:
{
"version": 1,
"format": "svg",
"changed_only": true,
"frame_count": 2,
"max_frames": 300,
"completed_reason": "stopped",
"viewport": { "width": 100, "height": 40 },
"frames": [
{
"index": 1,
"elapsed_ms": 0,
"files": ["frame-000001.svg"]
}
]
}
Keyboard and Mouse
Grafatui is designed for keyboard-first dashboard inspection.
Keyboard Controls
| Key | Action |
|---|---|
q | Quit |
r | Force refresh |
+ / - | Zoom out / in |
[ / ] | Pan left / right in time |
0 | Reset to live mode |
Up / Down or k / j | Select previous or next panel |
PgUp / PgDn | Scroll vertically, or select panels in fullscreen |
Home / End | Jump to top or bottom |
y | Toggle Y-axis mode |
g | Toggle autogrid guide lines |
a | Toggle external annotation markers |
t | Open the global annotation tag filter |
1 through 9 | Toggle series visibility |
f / Enter | Toggle fullscreen mode |
v | Toggle value inspection mode |
Enter in inspect mode | Open the selected panel’s annotation cluster at the cursor |
e | Export current view |
Ctrl+E | Start or stop changed-frame recording |
/ | Search panels |
Left / Right | Move cursor in inspect mode |
? | Toggle debug info |
Mouse Support
| Action | Behavior |
|---|---|
| Click | Select a panel, or move the cursor in fullscreen inspect mode |
| Drag | Move the cursor in fullscreen inspect mode |
| Scroll | Scroll the dashboard vertically |
In normal mode, clicking selects panels. Press v or f to use cursor-focused interactions.
Annotation Modals
The global tag filter opens with t. Use Up/Down or k/j to move,
Space to toggle the highlighted tag, c to clear the draft, Enter to apply
it, or Esc to discard it. In an annotation cluster, use Up/Down or
k/j to select an event, PgUp/PgDn to page, and Enter or Esc to
close it. Mouse input is ignored while either annotation modal is open.
Examples
The repository includes example Grafana dashboards and a local demo environment.
Demo Stack
Start Prometheus, node-exporter, and mock vLLM metrics:
cd examples/demo
docker-compose up -d
Run Grafatui from the repository root:
cargo run -- --grafana-json examples/dashboards/prometheus_demo.json --prometheus-url http://localhost:19090
Stop the demo:
cd examples/demo
docker-compose down -v
Included Dashboards
-
examples/dashboards/prometheus_demo.json: recommended first demo for the bundled Prometheus stack. -
examples/dashboards/all_visualizations.json: compact dashboard showing the supported visualization types, including timeseries bars, area fill, point mode, and hidden-axis examples. -
examples/dashboards/instant_queries.json: demonstrates explicit instant targets and the default instant behavior for summary panels. -
examples/dashboards/thresholds_demo.json: demonstrates thresholds, field bounds, and threshold marker rendering. -
examples/dashboards/grafana_v2_compatibility.json: exact Grafana V2 resource with aGridLayout, a dynamic Prometheusjobvariable, refresh settings, and two supported panels. Run it with:cargo run -- --grafana-json examples/dashboards/grafana_v2_compatibility.json --prometheus-url http://localhost:19090 -
examples/demo/vllm/grafana.json: vLLM-oriented dashboard for the mock demo services.
More Detail
See the repository example docs:
Grafana Dashboard JSON Compatibility
This document provides a comprehensive feature-parity table between the Grafana dashboard JSON models and what Grafatui currently supports.
Snapshot: Grafatui v0.1.11. The roadmap prioritizes Grafana parity first, then user-visible product value. See the roadmap for milestone slices built from this compatibility ladder.
Legend:
- ✅ Supported — Fully implemented and working
- 🔶 Partial — Partially implemented or with limitations
- ❌ Not Implemented — Recognized but not yet functional
- ⛔ Not Applicable — Cannot be implemented in a TUI context (e.g., browser-only features)
Dashboard Schema Models
Grafatui imports the non-resource Classic JSON model and a fixed-grid subset of the V2 Resource JSON model. In Grafana 13, use Export as code → Advanced options → Model: Classic as the fallback for advanced V2 dashboards. See the dashboard import guide for detailed steps.
| Model | Status | Notes |
|---|---|---|
| Classic JSON | ✅ Supported | Accepted by --grafana-json; the remaining tables describe support for its fields |
| V1 Resource JSON | ❌ Not Implemented | The Kubernetes-style dashboard.grafana.app/v1 resource envelope is not accepted |
| V2 Resource JSON | 🔶 Partial | JSON-only exact dashboard.grafana.app/v2 resources with GridLayout are supported |
| Resource YAML | ❌ Not Implemented | --grafana-json accepts JSON only |
V2 Resource JSON Subset
| V2 field or behavior | Status | Notes |
|---|---|---|
Exact apiVersion: dashboard.grafana.app/v2 | ✅ Supported | Other resource versions are rejected |
spec.layout.kind: GridLayout | ✅ Supported | GridLayoutItem coordinates map to Grafatui’s fixed 24-column grid |
Inline Panel elements | ✅ Supported | Supported panel visualization groups map through the Classic-equivalent importer |
Prometheus PanelQuery queries | ✅ Supported | Non-Prometheus datasources emit import diagnostics and are skipped |
Top-level spec.variables | 🔶 Partial | Supported variable kinds map to Grafatui variables; unsupported kinds emit diagnostics |
spec.timeSettings.autoRefresh | ✅ Supported | Used as the dashboard refresh interval |
vizConfig.spec.fieldConfig | 🔶 Partial | The supported Classic-equivalent field configuration subset applies |
| Rows, Tabs, and Auto-grid layouts | ❌ Not Implemented | Rejected as fatal import errors |
| Repeated grid items | ❌ Not Implemented | Rejected as fatal import errors |
| Conditional rendering, nested variables, and library panels | ❌ Not Implemented | Deferred V2 features |
Grafana V2 Resource YAML remains unsupported. Use a Classic export for any advanced V2 dashboard outside this fixed-grid subset.
Dashboard-Level Properties
| JSON Field | Status | Notes |
|---|---|---|
title | ✅ Supported | Displayed in the title bar |
uid | ❌ Not Implemented | Not used (not needed for local JSON import) |
id | ❌ Not Implemented | Not used |
version | ❌ Not Implemented | Not used |
tags | ❌ Not Implemented | Ignored |
timezone | ❌ Not Implemented | All timestamps displayed in UTC |
editable | ⛔ Not Applicable | Grafatui is read-only |
style | ⛔ Not Applicable | TUI has its own theme system |
schemaVersion | ❌ Not Implemented | Not validated |
refresh | ✅ Supported | Used as the default data refresh interval; overridden by config or --refresh-rate |
time | ❌ Not Implemented | Uses --range CLI option instead |
time.from / time.to | ❌ Not Implemented | Uses --range CLI option instead |
fiscalYearStartMonth | ⛔ Not Applicable | |
liveNow | ❌ Not Implemented | Uses 0 key to reset to live instead |
weekStart | ⛔ Not Applicable |
Panels
Panel Types
| Panel Type | Status | Notes |
|---|---|---|
graph (legacy) | ✅ Supported | Rendered as a line chart (Braille markers) |
timeseries | ✅ Supported | Mapped to graph renderer |
stat | ✅ Supported | Big value + sparkline |
gauge | ✅ Supported | Horizontal gauge bar |
bargauge | ✅ Supported | Vertical bar chart |
table | ✅ Supported | Two-column table (Series, Value) |
heatmap | ✅ Supported | Character-based block heatmap |
row | 🔶 Partial | Row panels are traversed for nested panels, but row headers/collapse are not rendered |
text | ❌ Not Implemented | Skipped during import |
dashlist | ❌ Not Implemented | Skipped during import |
alertlist | ❌ Not Implemented | Skipped during import |
news | ⛔ Not Applicable | |
annolist | ❌ Not Implemented | |
barchart | ❌ Not Implemented | Skipped (distinct from bargauge) |
candlestick | ❌ Not Implemented | |
canvas | ⛔ Not Applicable | Interactive canvas not feasible in TUI |
datagrid | ❌ Not Implemented | |
debug | ⛔ Not Applicable | |
geomap | ⛔ Not Applicable | Map visualization not feasible in TUI |
histogram | ❌ Not Implemented | |
logs | ❌ Not Implemented | |
nodeGraph | ⛔ Not Applicable | |
piechart | ❌ Not Implemented | |
state-timeline | ❌ Not Implemented | |
status-history | ❌ Not Implemented | |
trend | ❌ Not Implemented | |
xychart | ❌ Not Implemented |
Graph & Timeseries Parity
| Feature | JSON Field | Behavior | Grafana | Grafatui |
|---|---|---|---|---|
| Draw styles | fieldConfig.defaults.custom.drawStyle | Line, points, and bars map to terminal graph styles | 🟡 | ✅ |
| Point display | fieldConfig.defaults.custom.showPoints | always overlays visible point markers; never suppresses area/line point markers | 🟡 | 🔶 |
| Area fill | fieldConfig.defaults.custom.fillOpacity | Nonzero fill opacity renders terminal/SVG area fill behind the line | 🟡 | 🔶 |
| Stacking | fieldConfig.defaults.custom.stacking | Parsed and retained; non-off modes render non-stacked in this slice | 🟡 | 🔶 |
| Axis placement | fieldConfig.defaults.custom.axisPlacement | hidden suppresses y-axis labels; left/right map to the terminal y-axis | 🟡 | 🔶 |
| Axis grid | fieldConfig.defaults.custom.axisGridShow | Controls per-panel autogrid guide lines | 🟡 | ✅ |
| Threshold style | fieldConfig.defaults.custom.thresholdsStyle | Dashed/line style is parsed for graph threshold rendering | 🟡 | 🔶 |
Panel Common Fields
| JSON Field | Status | Notes |
|---|---|---|
title | ✅ Supported | Displayed as the panel border title |
type | ✅ Supported | Used to select the renderer |
gridPos | ✅ Supported | 24-column grid layout fully supported |
gridPos.x | ✅ Supported | |
gridPos.y | ✅ Supported | |
gridPos.w | ✅ Supported | |
gridPos.h | ✅ Supported | |
id | ❌ Not Implemented | Not used |
description | ❌ Not Implemented | Not displayed |
transparent | ⛔ Not Applicable | TUI panels always have borders |
links | ⛔ Not Applicable | No browser navigation |
repeat | ❌ Not Implemented | Template repeat not supported |
repeatDirection | ❌ Not Implemented | |
maxPerRow | ❌ Not Implemented | |
collapsed (row) | ❌ Not Implemented | Rows are always expanded |
panels (nested in row) | ✅ Supported | Nested panels are extracted recursively |
Targets (Queries)
| JSON Field | Status | Notes |
|---|---|---|
targets (array) | ✅ Supported | Multiple targets per panel supported |
targets[].expr | ✅ Supported | PromQL expression |
targets[].legendFormat | ✅ Supported | {{label}} syntax for legend formatting |
targets[].refId | ❌ Not Implemented | Not used |
targets[].datasource | ❌ Not Implemented | Only Prometheus datasource is supported |
targets[].interval | ❌ Not Implemented | Uses global --step instead |
targets[].intervalFactor | ❌ Not Implemented | |
targets[].instant | ✅ Supported | Uses Prometheus instant query when true; Gauge, BarGauge, and Table default to instant |
targets[].format | ❌ Not Implemented | Always treated as time_series |
targets[].hide | ✅ Supported | Hidden targets are skipped during import |
targets[].exemplar | ❌ Not Implemented | |
targets[].editorMode | ⛔ Not Applicable | UI-only setting |
PromQL Special Variables
| Variable | Status | Notes |
|---|---|---|
$__rate_interval | ✅ Supported | Computed as max(step × 4, 60s) |
$__rate_interval_ms | ✅ Supported | Millisecond form of $__rate_interval |
$__interval | ✅ Supported | Computed from the current range and panel resolution, bounded by --step |
$__interval_ms | ✅ Supported | Millisecond form of $__interval |
$__range | ✅ Supported | Current dashboard time range |
$__range_s | ✅ Supported | Current dashboard time range in seconds |
$__range_ms | ✅ Supported | Current dashboard time range in milliseconds |
Templating (Variables)
| JSON Field | Status | Notes |
|---|---|---|
templating.list | ✅ Supported | Variables extracted from dashboard |
templating.list[].name | ✅ Supported | Used as $var or ${var} in queries |
templating.list[].current.value | ✅ Supported | Used as default value |
templating.list[].current.text | 🔶 Partial | Used as fallback if value is missing |
templating.list[].allValue | ✅ Supported | Used when value is $__all, falls back to .* |
templating.list[].type | 🔶 Partial | query variables are resolved for Prometheus |
templating.list[].query | 🔶 Partial | Supports Prometheus label_values(...) and query_result(...) |
templating.list[].definition | 🔶 Partial | Used as a fallback query expression for dynamic query variables |
templating.list[].datasource | ❌ Not Implemented | |
templating.list[].regex | 🔶 Partial | Applied to dynamic query variable results |
templating.list[].sort | ❌ Not Implemented | |
templating.list[].multi | ❌ Not Implemented | Multi-value selection not supported |
templating.list[].includeAll | ❌ Not Implemented | |
templating.list[].refresh | 🔶 Partial | Dynamic variables refresh before panel queries |
templating.list[].options | ❌ Not Implemented | No dropdown/picker UI |
templating.list[].hide | ❌ Not Implemented | |
CLI --var KEY=VALUE override | ✅ Supported | Overrides dashboard defaults from command line |
Config file vars override | ✅ Supported | Overrides via TOML config |
Variable Substitution
| Pattern | Status | Notes |
|---|---|---|
$varname | ✅ Supported | Simple substitution |
${varname} | ✅ Supported | Braced substitution |
${varname:regex} | ❌ Not Implemented | Format modifiers not supported |
${varname:pipe} | ❌ Not Implemented | |
${varname:csv} | ❌ Not Implemented | |
${varname:json} | ❌ Not Implemented | |
${varname:queryparam} | ❌ Not Implemented | |
$__all | ✅ Supported | Replaced with allValue or .* |
Field Configuration (fieldConfig)
fieldConfig is partially implemented. Thresholds, explicit min/max bounds,
selected display formatting fields, threshold style, and per-panel autogrid
settings are parsed; value mappings, display names, and field overrides remain
major gaps.
| JSON Field | Status | Notes |
|---|---|---|
fieldConfig | 🔶 Partial | Parsed for supported defaults/custom fields below |
fieldConfig.defaults | 🔶 Partial | Parsed for min/max, thresholds, and selected custom fields |
fieldConfig.defaults.unit | 🔶 Partial | Common units such as bytes, bits, seconds, milliseconds, percent, percentunit, ops, request rate, and byte rate are formatted; unknown units fall back to Grafatui’s compact SI formatter |
fieldConfig.defaults.min | ✅ Supported | Used for Graph y-axis lower bounds, percentage thresholds, and Gauge limits |
fieldConfig.defaults.max | ✅ Supported | Used for Graph y-axis upper bounds, gauge scaling, and threshold boundaries |
fieldConfig.defaults.decimals | ✅ Supported | Controls numeric precision in panel values, graph axes, legends, and exports |
fieldConfig.defaults.color | ❌ Not Implemented | Uses theme palette instead |
fieldConfig.defaults.mappings | ❌ Not Implemented | Value mappings not supported; import diagnostics warn when mappings are ignored |
fieldConfig.defaults.noValue | 🔶 Partial | Used for null Stat/Table values and exports; empty panels still show Grafatui’s No data state |
fieldConfig.defaults.displayName | ❌ Not Implemented | |
fieldConfig.defaults.custom | 🔶 Partial | Used for graph draw style, fill/points, axis placement, stacking metadata, threshold style, and axis grid visibility |
fieldConfig.defaults.custom.lineWidth | ❌ Not Implemented | TUI limitation |
fieldConfig.defaults.custom.fillOpacity | 🔶 Partial | Nonzero values enable terminal/SVG area fill; exact browser opacity is approximated |
fieldConfig.defaults.custom.pointSize | ⛔ Not Applicable | TUI points use fixed terminal-cell markers |
fieldConfig.defaults.custom.axisLabel | ❌ Not Implemented | |
fieldConfig.defaults.custom.axisGridShow | ✅ Supported | Controls per-panel autogrid guide lines for graph/time-series panels |
fieldConfig.defaults.custom.thresholdsStyle | 🔶 Partial | mode is parsed for threshold rendering; glyph style is also controlled by Grafatui’s marker setting |
fieldConfig.defaults.custom.scaleDistribution | ❌ Not Implemented | Always linear |
fieldConfig.overrides | ❌ Not Implemented |
Thresholds
| JSON Field | Status | Notes |
|---|---|---|
fieldConfig.defaults.thresholds | ✅ Supported | Applied to Graph limit lines and dynamic coloring for Stat, Gauge & BarGauge |
fieldConfig.defaults.thresholds.mode | ✅ Supported | (absolute / percentage) |
fieldConfig.defaults.thresholds.steps | ✅ Supported | |
fieldConfig.defaults.thresholds.steps[].value | ✅ Supported | Evaluated mathematically against metric values |
fieldConfig.defaults.thresholds.steps[].color | ✅ Supported | Maps keywords (e.g., green) and hex codes (e.g., #FF0000) |
Panel Options (options)
Panel-specific options are not parsed yet. Grafatui currently applies its own
compact TUI defaults for legends, stat sparklines, gauges, and inspect-mode
tooltips.
| JSON Field | Status | Notes |
|---|---|---|
options | ❌ Not Implemented | Panel-specific options object is ignored |
options.legend | ❌ Not Implemented | Grafatui uses its own compact legend |
options.legend.displayMode | ❌ Not Implemented | Always shows inline legend |
options.legend.placement | ❌ Not Implemented | Always bottom |
options.legend.calcs | ❌ Not Implemented | No calculated legend values (min/max/avg) |
options.tooltip | ❌ Not Implemented | Inspect mode serves as tooltip substitute |
options.tooltip.mode | ❌ Not Implemented | |
options.orientation | ❌ Not Implemented | |
options.reduceOptions | ❌ Not Implemented | Stat/Gauge always use last value; import diagnostics warn when reduce options are ignored |
options.reduceOptions.calcs | ❌ Not Implemented | |
options.reduceOptions.fields | ❌ Not Implemented | |
options.textMode | ❌ Not Implemented | |
options.colorMode | ❌ Not Implemented | |
options.graphMode | ❌ Not Implemented | Stat always shows sparkline |
Annotations
| JSON Field | Status | Notes |
|---|---|---|
annotations | ❌ Not Implemented | External file/command providers do not implement this Grafana field. |
annotations.list | ❌ Not Implemented | External file/command providers do not implement this Grafana field. |
Grafatui external file/command JSONL events are a separate, opt-in read-only source.
panel_titles is Grafatui’s external-source routing field: it matches eligible
graph/timeseries panel titles exactly, not Grafana panel IDs. It does not imply
compatibility with Grafana annotation queries, APIs, annotations, or
annotations.list.
Data Links & Transformations
| JSON Field | Status | Notes |
|---|---|---|
options.dataLinks | ⛔ Not Applicable | No browser navigation in TUI |
transformations | ❌ Not Implemented | |
transformations[].id | ❌ Not Implemented | (e.g., organize, merge, reduce) |
Alert Rules
| JSON Field | Status | Notes |
|---|---|---|
alert | ❌ Not Implemented | Panel-level alerts |
alert.conditions | ❌ Not Implemented | |
alert.notifications | ❌ Not Implemented |
Datasource Configuration
| Feature | Status | Notes |
|---|---|---|
Prometheus (query_range) | ✅ Supported | Primary and only supported datasource |
Prometheus (query instant) | ✅ Supported | Used for dynamic template variables and instant panel targets |
| Prometheus labels API | ✅ Supported | Used for dynamic variable label_values(...) |
| Mixed datasource | ❌ Not Implemented | |
| InfluxDB | ❌ Not Implemented | |
| Loki | ❌ Not Implemented | |
| Elasticsearch | ❌ Not Implemented | |
| Other datasources | ❌ Not Implemented |
Summary Statistics
| Category | Supported | Partial | Not Implemented | Not Applicable |
|---|---|---|---|---|
| Dashboard Properties | 1 | 0 | 10 | 4 |
| Panel Types | 7 | 1 | 14 | 5 |
| Panel Common Fields | 8 | 0 | 6 | 2 |
| Targets / Queries | 3 | 0 | 8 | 1 |
| PromQL Variables | 7 | 0 | 0 | 0 |
| Templating | 6 | 6 | 6 | 0 |
| Variable Substitution | 3 | 0 | 5 | 0 |
| Field Config | 4 | 6 | 10 | 2 |
| Thresholds | 5 | 0 | 0 | 0 |
| Panel Options | 0 | 0 | 14 | 0 |
| Annotations | 0 | 0 | 2 | 0 |
| Data Links / Transforms | 0 | 0 | 2 | 1 |
| Alert Rules | 0 | 0 | 3 | 0 |
| Datasources | 3 | 0 | 5 | 0 |
| Total | 47 | 13 | 85 | 15 |
Most Requested Missing Features
Based on user feedback, the following missing features are most commonly expected:
- Value mappings (
fieldConfig.defaults.mappings) — Map numeric values to text labels - Broader unit formatting (
fieldConfig.defaults.unit) — Extend the current common-unit subset to more Grafana unit families - Reduce options (
options.reduceOptions) — Use min/max/mean/total instead of always using the latest value - Import diagnostics — Warn clearly about skipped panel types and ignored high-impact fields
- Additional panel types —
text,piechart,histogram,logs
What Grafatui Does Instead
Grafatui provides several TUI-native capabilities that don’t map directly to Grafana JSON features:
| Grafatui Feature | Description |
|---|---|
| 8 color themes | default, dracula, monokai, solarized-dark, solarized-light, gruvbox, tokyo-night, catppuccin |
| Keyboard navigation | Vim-style (j/k), arrow keys, page up/down |
| Panel search | / opens a fuzzy-search popup |
| Fullscreen mode | f to focus on a single panel |
| Inspect mode | v enables cursor-based point-in-time inspection |
| Y-axis toggle | y switches between auto-scale and zero-based |
| Series toggling | 1–9 to show/hide individual series |
| Autogrid toggle | g toggles automatic guide lines |
| Mouse support | Click to select, scroll to navigate, drag cursor in fullscreen |
| Smart caching | Request deduplication and caching for identical queries |
| Client-side downsampling | Max-pooling to ~200 points to preserve peaks |
| SVG/PNG export and recordings | Save dashboard snapshots or changed-frame recording bundles |
| TOML configuration | Persistent config file for all CLI options |
This document was reviewed against the Grafatui source code at v0.1.11. If you notice any inaccuracies, please open an issue or PR.
Troubleshooting
Prometheus Connection Refused
Check that Prometheus is running and reachable:
curl http://localhost:9090/-/healthy
If you are using the demo stack, the Prometheus port is 19090:
curl http://localhost:19090/-/healthy
No Data Appears
Prometheus may need a few scrape intervals before data is available. Wait 10 to 15 seconds and force a refresh with r.
Also confirm that the dashboard queries match labels in your Prometheus server:
grafatui --prometheus-url http://localhost:9090 --grafana-json ./dashboard.json --var job=prometheus
Dashboard Variables Do Not Match
Override variables explicitly with --var:
grafatui --grafana-json ./dashboard.json --var instance=localhost:9090
If a Grafana dashboard uses multi-select formatting modifiers such as ${var:csv} or ${var:regex}, check the compatibility matrix. Not every Grafana interpolation mode is implemented.
Demo Port Conflict
The demo Prometheus service uses host port 19090. If that port is already in use, edit examples/demo/docker-compose.yml and run Grafatui with the updated URL.
Export Directory Problems
Set an explicit export directory:
grafatui --export-dir ./grafatui-exports
Make sure the directory is writable by your current user.