kibana-vega

Create and manage Kibana dashboards and Vega visualizations with ES|QL data sources.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "kibana-vega" with this command: npx skills add elastic/agent-skills/elastic-agent-skills-kibana-vega

Kibana Vega

Create and manage Kibana dashboards and Vega visualizations with ES|QL data sources.

Overview

Vega is a declarative visualization grammar for creating custom charts in Kibana. Combined with ES|QL queries, it enables highly customized visualizations beyond standard Kibana charts.

Important Version Requirement: This skill strictly supports ES|QL data sources and requires Serverless Kibana or version 9.4+ (SNAPSHOT). It will not work reliably on older versions or with older Lucene/KQL data source definitions.

Quick Start

Environment Configuration

Kibana connection is configured via environment variables. Run node scripts/kibana-vega.js test to verify the connection. If the test fails, suggest these setup options to the user, then stop. Do not try to explore further until a successful connection test.

Option 1: Elastic Cloud (recommended for production)

export KIBANA_CLOUD_ID="deployment-name:base64encodedcloudid" export KIBANA_API_KEY="base64encodedapikey"

Option 2: Direct URL with API Key

export KIBANA_URL="https://your-kibana:5601" export KIBANA_API_KEY="base64encodedapikey"

Option 3: Basic Authentication

export KIBANA_URL="https://your-kibana:5601" export KIBANA_USERNAME="elastic" export KIBANA_PASSWORD="changeme"

Option 4: Local Development with start-local

For local development and testing, use start-local to quickly spin up Elasticsearch and Kibana using Docker or Podman:

curl -fsSL https://elastic.co/start-local | sh

After installation completes, Elasticsearch runs at http://localhost:9200 and Kibana at http://localhost:5601 . The script generates a random password for the elastic user, stored in the .env file inside the created elastic-start-local folder.

To configure the environment variables for this skill, source the .env file and export the connection settings:

source elastic-start-local/.env export KIBANA_URL="$KB_LOCAL_URL" export KIBANA_USERNAME="elastic" export KIBANA_PASSWORD="$ES_LOCAL_PASSWORD"

Then run node scripts/kibana-vega.js test to verify the connection.

Optional: Skip TLS verification (development only)

export KIBANA_INSECURE="true"

Basic Workflow

Test connection

node scripts/kibana-vega.js test

Create visualization directly from stdin (no intermediate file needed)

echo '<json-spec>' | node scripts/kibana-vega.js visualizations create "My Chart" -

Get visualization spec for review/modification

node scripts/kibana-vega.js visualizations get <vis-id>

Update visualization from stdin

echo '<json-spec>' | node scripts/kibana-vega.js visualizations update <vis-id> -

Create dashboard

node scripts/kibana-vega.js dashboards create "My Dashboard"

Add visualization with grid position

node scripts/kibana-vega.js dashboards add-panel <dashboard-id> <vis-id> --x 0 --y 0 --w 24 --h 15

Apply a complete layout from stdin

echo '<layout-json>' | node scripts/kibana-vega.js dashboards apply-layout <dashboard-id> -

Note: Use - as the file argument to read JSON from stdin. This enables direct spec creation without intermediate files.

Minimal Vega Spec with ES|QL

IMPORTANT: Always use proper JSON format (not HJSON with triple quotes) to avoid parse errors.

{ "$schema": "https://vega.github.io/schema/vega-lite/v6.json", "title": "My Chart", "autosize": { "type": "fit", "contains": "padding" },

"config": { "axis": { "domainColor": "#444", "tickColor": "#444" }, "view": { "stroke": null } },

"data": { "url": { "%type%": "esql", "query": "FROM logs-* | STATS count = COUNT() BY status | RENAME status AS category" } },

"mark": { "type": "bar", "color": "#6092C0" }, "encoding": { "x": { "field": "category", "type": "nominal" }, "y": { "field": "count", "type": "quantitative" } } }

ES|QL Data Source Options

| Property | Description | | --------------------------- | ------------------------------------------ | --------- | | %type%: "esql" | Required. Use ES | QL parser | | %context%: true | Apply dashboard filters | | %timefield%: "@timestamp" | Enable time range with ?_tstart /?_tend |

Examples

Stdin Examples

Create visualization directly from JSON

echo '{"$schema":"https://vega.github.io/schema/vega-lite/v6.json",...}' |
node scripts/kibana-vega.js visualizations create "My Chart" -

Update visualization

echo '{"$schema":...}' | node scripts/kibana-vega.js visualizations update <id> -

Apply layout directly

echo '{"panels":[{"visualization":"<id>","x":0,"y":0,"w":24,"h":10}]}' |
node scripts/kibana-vega.js dashboards apply-layout <dash-id> -

Dashboard Layout Design

Grid System

Kibana dashboards use a 48-column grid:

Width Columns Use Case

Full 48 Timelines, heatmaps, wide charts

Half 24 Side-by-side comparisons

Third 16 Three-column layouts

Quarter 12 KPI metrics, small summaries

Above the Fold (Critical)

Primary information must be visible without scrolling.

Resolution Visible Height Layout Budget

1080p ~30 units 2 rows: h:10 + h:12

1440p ~40 units 3 rows: h:12 + h:12 + h:12

Height guidelines:

  • h: 10 — Compact bar charts (≤7 items), fits above fold

  • h: 12-13 — Standard charts, timelines

  • h: 15+ — Detailed views, use below fold

Layout Pattern: Operational Dashboard

┌───────────────────────┬───────────────────────┐ y:0 │ Current State A │ Current State B │ h:10 (compact) ├───────────────────────┴───────────────────────┤ y:10 │ Primary Timeline │ h:12 (main trend) ├ ─ ─ ─ ─ ─ ─ ─ FOLD ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ y:22 (1080p fold) │ Secondary Timeline │ h:12 (below fold OK) ├───────────────────────┬───────────────────────┤ y:34 │ Complementary 1 │ Complementary 2 │ h:10 └───────────────────────┴───────────────────────┘

Creating Layouts

Option 1: Add panels with positions

Row 1: Two compact half-width charts (above fold)

node scripts/kibana-vega.js dashboards add-panel $DASH $VIS1 --x 0 --y 0 --w 24 --h 10 node scripts/kibana-vega.js dashboards add-panel $DASH $VIS2 --x 24 --y 0 --w 24 --h 10

Row 2: Full-width timeline (above fold)

node scripts/kibana-vega.js dashboards add-panel $DASH $VIS3 --x 0 --y 10 --w 48 --h 12

Row 3: Below fold content

node scripts/kibana-vega.js dashboards add-panel $DASH $VIS4 --x 0 --y 22 --w 48 --h 12

Option 2: Apply layout file

Create layout.json :

{ "title": "My Dashboard", "panels": [ { "visualization": "<vis-id-1>", "x": 0, "y": 0, "w": 24, "h": 10 }, { "visualization": "<vis-id-2>", "x": 24, "y": 0, "w": 24, "h": 10 }, { "visualization": "<vis-id-3>", "x": 0, "y": 10, "w": 48, "h": 12 }, { "visualization": "<vis-id-4>", "x": 0, "y": 22, "w": 48, "h": 12 } ] }

Apply it:

node scripts/kibana-vega.js dashboards apply-layout <dashboard-id> layout.json

Design Checklist

  • Above the fold: Primary info in top ~22 height units (1080p)

  • Compact heights: Use h:10 for bar charts with ≤7 items

  • Prioritize: Most important info top-left

  • Group: Related charts side-by-side for comparison

  • Timelines: Full width (w:48), h:12 for compact

  • Below fold: Complementary/detailed panels OK to scroll

Guidelines

Use JSON, not HJSON triple-quotes — ''' multi-line strings cause parse errors in Kibana; use single-line queries with escaped quotes "

Rename dotted fields — room.name breaks Vega (interpreted as nested path); use ES|QL RENAME room.name AS room

Don't set width/height — use autosize: { type: fit, contains: padding }

Set labelLimit on axes — horizontal bar chart labels truncate; use axis: { "labelLimit": 150 }

Sort bars by value — pre-sort in ES|QL with SORT field DESC and use sort: null in encoding (preserves data order); avoid sort: "-x" in layered specs (bar + text labels) as it causes "conflicting sort properties" warnings

Time axis: no rotated labels — use axis: { "labelAngle": 0, "tickCount": 8 } , let Vega auto-format dates

Descriptive titles replace axis titles — good title/subtitle makes axis titles redundant; use title: null on axes

Use color sparingly — color is a precious visual attribute; use a single default color (#6092C0 ) for bar charts where position already encodes value; reserve color encoding for categorical distinction (e.g., multiple lines in a time series)

Dark theme compatibility — always include config to avoid bright white borders:

"config": { "axis": { "domainColor": "#444", "tickColor": "#444" }, "view": { "stroke": null } }

CLI Commands

Dashboards

node scripts/kibana-vega.js dashboards list [search] node scripts/kibana-vega.js dashboards get <id> node scripts/kibana-vega.js dashboards create <title> node scripts/kibana-vega.js dashboards delete <id> node scripts/kibana-vega.js dashboards add-panel <dash-id> <vis-id> [--x N] [--y N] [--w N] [--h N] node scripts/kibana-vega.js dashboards apply-layout <dash-id> <file|->

Visualizations (use - for stdin instead of file)

node scripts/kibana-vega.js visualizations list [vega] node scripts/kibana-vega.js visualizations get <id> node scripts/kibana-vega.js visualizations create <title> <file|-> node scripts/kibana-vega.js visualizations update <id> <file|-> node scripts/kibana-vega.js visualizations delete <id>

Full Documentation

  • Dashboard Layout Reference — Grid system, layout patterns, design best practices

  • Vega-Lite Reference — Complete Vega-Lite grammar, chart patterns, best practices

  • ES|QL in Vega Reference — ES|QL data source configuration, time filtering, parameters

  • Example Specs — Ready-to-use chart templates

Common Issues

Error Solution

"End of input while parsing an object" Don't use HJSON ''' triple-quotes; use JSON with single-line queries

Labels show "undefined" Rename dotted fields: RENAME room.name AS room

Bars invisible / not rendering Remove complex scale.domain , use simpler color schemes

Y-axis labels truncated Add axis: { "labelLimit": 150 } to encoding

Panels stacked vertically Use --x --y --w --h options or apply-layout command

"width/height ignored" Remove dimensions, use autosize

Bright white borders on dark theme Add config: { "view": { "stroke": null }, "axis": { "domainColor": "#444", "tickColor": "#444" } }

"401 Unauthorized" Check KIBANA_USERNAME/PASSWORD

"conflicting sort properties" Don't use sort: "-x" in layered specs; pre-sort in ES|QL and use sort: null

"404 Not Found" Verify dashboard/visualization ID

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

elasticsearch-esql

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

kibana-dashboards

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

elasticsearch-authn

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

kibana-agent-builder

No summary provided by upstream source.

Repository SourceNeeds Review