Build line charts with Kibana
Line charts are ideal for visualizing how metrics evolve over time, spotting seasonal patterns, and detecting spikes or regressions at a glance. Use them for KPIs like response time, error rate, throughput, or utilization, and compare multiple series or previous periods on the same chart. You can create line charts from any numeric data using aggregations (for example, Average, Percentile, Counter rate) or with custom formulas.
You can create line charts in Kibana using Lens.

Before you start, make sure you have data indexed into Elasticsearch or install sample data. By default, Lens uses data views to access your Elasticsearch data. Data views are created automatically in most cases when you ingest data. You can also create one manually to select just the data that you want. Alternatively, you can use the ES|QL query mode to query your Elasticsearch data directly.
To build a line chart:
-
Access Lens
Lens is Kibana's main visualization editor. You can access it:
- From a dashboard: On the Dashboards page, open or create the dashboard where you want to add the visualization, then add a new visualization.
- From the Visualize library page by creating a new visualization.
-
Set the visualization to Line
Make sure that the visualization type is set to Line.
When you drag a date or time field (such as @timestamp) onto an empty workspace, Line is automatically selected. -
Define the data to show
- Select the data view that contains your data.
- Drag a time field to the Horizontal axis and a numeric field to the Vertical axis. Kibana automatically selects an appropriate aggregation function compatible with the selected field.
Optionally:
- Add more numeric fields to create additional series, or drag a categorical field to Break down by to split the series.
- You can click the Add layer icon to integrate additional visualizations, annotations, or a reference line.
The chart preview updates to show one or more lines plotted over time. Each line represents a series, and data points are connected to show trends.
-
Customize the chart to follow best practices
You can tweak the appearance of your chart by adjusting axes, legends, and series styles from the chart settings. Consider the following best practices:
- Use color wisely
-
Assign colors that match your users' expectations and consider your specific context.
Lens automatically applies the Elastic (line optimized) palette to line charts, which reorders colors for better contrast between adjacent series. You can override this by manually selecting a different palette. - Provide context
- Add a legend and descriptive axis titles, or remove them for obvious axes.
For more chart configuration options, go to the Line chart settings section.
For panel sizing and layout guidance, refer to Organize dashboard panels.
-
Save the chart
- If you accessed Lens from a dashboard, select Save and return to save the visualization and add it to that dashboard, or select Save to library to add the visualization to the Visualize library and be able to add it to other dashboards later.
- If you accessed Lens from the Visualize library, select Save. A menu opens and lets you add the visualization to a dashboard and to the Visualize library.
In line charts, you can enable time shift to compare the current value with a prior time range and identify deltas.

- Create a line chart with a time-based Horizontal axis and your main metric on Vertical axis, for example:
bytes. - Duplicate the layer:
-
Select Duplicate layer from the visualization editor. -
Open the contextual menu of the visualization editor and select Duplicate layer.
-
- From the duplicated layer settings, select the field defined as vertical axis to open its details. Expand its Advanced options and set Time shift to
1wor to the time value of your choice. Check Compare differences over time for more details. - Optionally, customize the appearance of the layer to adjust how it looks on the chart. When you duplicate a layer, Kibana automatically assigns a different Series color to the new layer. You can for example change this color, or adjust the layer's name and axis position. This name is used for the chart's legend.
You can also compute the relative change by defining the axis data with a formula, for example:
(average(bytes) - average(bytes, shift='1w')) / average(bytes, shift='1w')
Use reference lines to indicate important thresholds, such as SLOs or alert limits.

- In the chart settings, add a static value reference line to mark your target or threshold visually.
- Use the Text decoration setting to provide a name, for example,
TargetorSLO, choose a color, and optionally a band.
Customize your line chart to display exactly the information you need, formatted the way you want.
- Data
-
- Functions:
- Top values: Show the most common values of a field.
- Field: Select the field to group by. You can add up to 4 fields to create multi-term groups. When multiple fields are selected, each group represents a unique combination of values across those fields. You can reorder the fields by dragging them to change their priority.
- Number of values: How many top values to display. The default number of values depends on your environment:
-
Defaults to 9. -
Defaults to 5 for the first Top values dimension added to the chart and 3 for each additional one.
-
- Rank by: Specifies the dimension the top values are ranked by. Available options:
- Count of records: Rank by the number of documents containing each value. This is the default when a metric is defined.
- Alphabetical: Rank by the term key alphabetically. This is the default when no metric is defined.
- Rarity: Find terms that appear in very few documents, using a rare terms aggregation. You can configure the Max doc count per term to set the maximum number of documents a term can appear in to be considered rare (default: 1, max: 100). Available for single-field terms only, and not for floating-point numeric fields (
float,double,half_float, andscaled_float). - Significance: Find statistically unusual terms compared to the overall data set, using a significant terms aggregation. Only available for
keywordfields and single-field terms. - Custom: Define a custom metric aggregation to rank by (for example, rank by the sum of a numeric field rather than by count).
- Rank direction: Ascending or descending order. Disabled when Rank by is set to Rarity or Significance.
Advanced settingsSeveral advanced options allow you to refine the behavior of the breakdown:
- Include documents without the selected field: Off by default.
- Group remaining values as "Other": On by default.
- Enable accuracy mode: This option improves results for high-cardinality data, but increases the load on the Elasticsearch cluster.
- Include values: Values from the dimension to always include, even if they aren't among the top values. You can enter exact values or a regular expression.
- Exclude values: Values from the dimension to always exclude. You can enter exact values or a regular expression.
- Date histogram: Group data into time-based buckets.
- Field: Select the date field to use for the time-based grouping.
Include empty rows: This option is on by default. Turn it off to exclude empty rows from the data.
Bind to global time picker: Associate the selected field to the Lens or dashboard main time selector.
Minimum interval: Define the time interval for aggregating the data. For example,
30s,20m,24h,2d,1w,1MDrop partial intervals: Exclude incomplete intervals from the data. This option is off by default.
- Intervals: Create numeric ranges for continuous data by grouping a numeric field into buckets.
- Field: Select the numeric field to create intervals from.
- Intervals granularity: Use the slider to control how many intervals to create. Kibana divides the field into evenly spaced intervals (incremented by 10, 5, or 2) between the field's minimum and maximum values. The minimum granularity is 1, and the maximum is set by the
histogram:maxBarsadvanced setting. - Create custom ranges: Define your own ranges with specific lower and upper bounds and optional labels, instead of using the automatic granularity.
- Include empty rows: Include intervals that contain no matching documents. On by default.
- Filters: Define custom KQL filters. Each filter creates one group from the documents that match its query.
- Top values: Show the most common values of a field.
- Functions:
- Appearance
- Name: By default, the chart uses the function or formula as title. It's a best practice to customize this with a meaningful title.
- Data
-
To represent the metrics or values you want to visualize, you can use quick functions like
Average,Count,Percentile,Counter rate, or create custom calculations with formulas. Refer to Lens visualizations > Use formulas to perform math for examples, or to the Formula reference available from Lens.Advanced settingsDepending on the data you defined, several options allow you to apply additional filtering to the data taken into account to compute the final value to show.
Based on the type of visualization you're creating, only some of the following options can be available:
- Normalize by unit: Normalize the metric values to show per unit of time.
- Filter by: Specify a query.
- Reduced time range: Reduce the time range specified on the dashboard's time filter by the specified duration.
- Time shift: Shift the time range by the specified duration. This is useful if the value should use a different time range than the one selected on the dashboard.
- Hide zero values: Don't show values equal to zero. This option is on by default.
Appearance
- Name: Customize the legend label with a descriptive name.
- Value format: Control how numeric values are displayed on the vertical axis of your visualization.
- Series color: Select a palette or specific color per series.
- Axis side: Control where axis labels and tick marks appear.
Breakdown functions segment your data into multiple lines on the same chart, with each line representing a different value of a categorical field. You can specify the following options:
- Data
-
- Functions:
- Top values: Show the most common values of a field.
- Field: Select the field to group by. You can add up to 4 fields to create multi-term groups. When multiple fields are selected, each group represents a unique combination of values across those fields. You can reorder the fields by dragging them to change their priority.
- Number of values: How many top values to display. The default number of values depends on your environment:
-
Defaults to 9. -
Defaults to 5 for the first Top values dimension added to the chart and 3 for each additional one.
-
- Rank by: Specifies the dimension the top values are ranked by. Available options:
- Count of records: Rank by the number of documents containing each value. This is the default when a metric is defined.
- Alphabetical: Rank by the term key alphabetically. This is the default when no metric is defined.
- Rarity: Find terms that appear in very few documents, using a rare terms aggregation. You can configure the Max doc count per term to set the maximum number of documents a term can appear in to be considered rare (default: 1, max: 100). Available for single-field terms only, and not for floating-point numeric fields (
float,double,half_float, andscaled_float). - Significance: Find statistically unusual terms compared to the overall data set, using a significant terms aggregation. Only available for
keywordfields and single-field terms. - Custom: Define a custom metric aggregation to rank by (for example, rank by the sum of a numeric field rather than by count).
- Rank direction: Ascending or descending order. Disabled when Rank by is set to Rarity or Significance.
Advanced settingsSeveral advanced options allow you to refine the behavior of the breakdown:
- Include documents without the selected field: Off by default.
- Group remaining values as "Other": On by default.
- Enable accuracy mode: This option improves results for high-cardinality data, but increases the load on the Elasticsearch cluster.
- Include values: Values from the dimension to always include, even if they aren't among the top values. You can enter exact values or a regular expression.
- Exclude values: Values from the dimension to always exclude. You can enter exact values or a regular expression.
- Date histogram: Group data into time-based buckets.
- Field: Select the date field to use for the time-based grouping.
Include empty rows: This option is on by default. Turn it off to exclude empty rows from the data.
Bind to global time picker: Associate the selected field to the Lens or dashboard main time selector.
Minimum interval: Define the time interval for aggregating the data. For example,
30s,20m,24h,2d,1w,1MDrop partial intervals: Exclude incomplete intervals from the data. This option is off by default.
- Intervals: Create numeric ranges for continuous data by grouping a numeric field into buckets.
- Field: Select the numeric field to create intervals from.
- Intervals granularity: Use the slider to control how many intervals to create. Kibana divides the field into evenly spaced intervals (incremented by 10, 5, or 2) between the field's minimum and maximum values. The minimum granularity is 1, and the maximum is set by the
histogram:maxBarsadvanced setting. - Create custom ranges: Define your own ranges with specific lower and upper bounds and optional labels, instead of using the automatic granularity.
- Include empty rows: Include intervals that contain no matching documents. On by default.
- Filters: Define custom KQL filters. Each filter creates one group from the documents that match its query.
- Top values: Show the most common values of a field.
- Collapse by: Aggregate all metric values that share the same value for this dimension into a single number, removing it as an independent grouping. Available aggregation methods:
Sum,Min,Max, orAverage.
- Functions:
- Appearance
-
Allow you to customize how your breakdown data is displayed in line charts, including:
- Name: It's a best practice to customize this with a meaningful title.
- Value format: Control how numeric values are displayed in your visualization.
- Color mapping: Determine how colors are assigned to your breakdown series.
When creating or editing a visualization, you can adjust the following settings.
Style
Adjust the visual appearance of your line chart to control how the data series are labeled and displayed alongside your chart. Click to open the Style panel.
- Appearance
- Allow you to customize to overall chart appearance:
Point visibility: Use this option to show or hide data points. Set to Auto by default: Points are visible unless the distance between them is too short.
- Line interpolation: Choose how to interpolate the line between data points from the available options: Straight (default), Smooth, and Step.
- Left axis
- Allow you to customize the Y-axis appearance.
- Axis Title. Show, hide or add a custom title.
- Gridlines. Show or hide gridlines.
- Tick labels. Show or hide tick labels.
- Orientation. Choose the tick labels orientation.
- Axis scale. Choose an axis scale type. Options include: Linear (default), Logarithmic, and Square root.
- Bounds. Use Bounds to set the minimum and maximum values for the Y-axis. Options include: Full, Data, and Custom
- Round to nice value. Axis labels can be rounded to more readable numbers.
- Bottom axis
- Allow you to customize the bottom axis appearance:
- Axis Title. Show, hide or add a custom title.
- Gridlines. Show/hide gridlines.
- Tick labels. Show/hide tick labels.
- Show partial data markers: indicate data points where Data collection is incomplete (the time bucket is still open and actively collecting events), or data may change (the values represented might increase as more data arrives).
- Show current time marker: Add a vertical line on your chart that represents the current time.
Missing values
Use Missing values to control how gaps appear in area and line charts. Missing values include empty buckets and metrics that return null because of their operation or data.
This setting is available when Include empty rows is enabled or when a metric produces a null bucket. For example, a moving average can produce null buckets.
This setting isn't available for percentage area charts or charts created from ES|QL queries.
Hide: Don't show gaps in the data.

Zero: Connect the data points before and after each gap to zero.

Linear: Connect the data points before and after each gap with a straight line.

Last: Fill each gap with a horizontal or vertical line from the last available data point.

Next: Fill each gap with a horizontal or vertical line from the next available data point.

- End values
-
Choose how to extend a series to the edge of the chart:
- Hide: Don't extend the series.
- Zero: Extend the series as zero.
- Nearest: Extend the series using its first or last value.
- Show as dotted line
- Show the lines used to fill gaps as dotted lines.
Legend
You can customize the way the legend is displayed and the data it shows. Select to open the Legend panel.
Use Visibility and Position to control where the legend appears. For legends positioned outside the chart on the left or right, use Width to set the legend size.
- Layout
-
For legends positioned outside the chart at the top or bottom, choose how series labels are arranged:
- List: A compact layout that flows series labels to fit the available space. List is the default for new charts when the legend is at the top or bottom.
- Grid: A table-style layout that aligns series labels and statistics into rows and columns.
Existing visualizations retain their layout until you change it.
- Statistics
-
When every chart layer uses a non-categorical horizontal axis, such as a date, time, or numeric axis, select one or more statistics to show for each series:
- Average: Average of all values.
- Median: Median value.
- Minimum: Minimum value.
- Maximum: Maximum value.
- Range: Difference between the minimum and maximum values.
- Last value: Last value.
- Last non-null value: Last value that isn't null.
- First value: First value.
- First non-null value: First value that isn't null.
- Difference: Difference between the first and last values.
- Difference %: Percentage difference between the first and last values.
- Sum: Sum of all values.
- Count: Number of values.
- Distinct count: Number of distinct values.
- Variance: Variance of all values.
- Std deviation: Standard deviation of all values.
- Current or last value: Value of the data point under the pointer, or the last value when the pointer isn't over a data point.
All statistics use the aggregated data points shown for the selected time range, not the original documents from Elasticsearch. After you select a statistic that uses the Grid layout, you can add a Series header above the legend entries.
- Label truncation
- For legends positioned inside the chart, outside on the side, or outside at the top or bottom with the Grid layout, choose whether to truncate long series labels and set the maximum number of lines for each label.
- Average RAM per host
- Monitoring the average of RAM over time for the first four hosts:
- Drag
@timestampto the Horizontal axis and set the following settings:- Functions:
Date histogram - Minimum interval:
Hour
- Functions:
- Drag
machine.ramto the Vertical axis and set the following settings:- Functions: :
Moving average - Value format:
Bytes
- Functions: :
- In the Breakdwon panel, set the following settings:
- Functions:
Top values - Fields:
host.keyword - Number of values:
4
- Functions:
- Save your chart.

Create this chart using the API
Send the following request to create a line chart that plots the moving average of RAM, broken down by the top 4 hosts.
POST kbn://api/visualizations
{
"type": "xy",
"title": "Average RAM per host",
"filters": [],
"query": { "expression": "" },
"legend": { "visibility": "visible", "placement": "outside", "position": "bottom" },
"axis": {},
"layers": [
{
"type": "line",
"x": {
"operation": "date_histogram",
"field": "timestamp",
"suggested_interval": "1h"
},
"y": [
{
"operation": "moving_average",
"of": {
"operation": "average",
"field": "machine.ram",
"format": { "type": "bytes", "decimals": 0 },
"filter": { "expression": "" }
},
"label": "Moving average of RAM",
"format": { "type": "bytes", "decimals": 0 },
"filter": { "expression": "" },
"color": {
"type": "static",
"color": "#6092c0"
}
}
],
"breakdown_by": {
"operation": "terms",
"fields": ["host.keyword"],
"limit": 4,
"rank_by": { "type": "alphabetical", "direction": "asc" }
},
"data_source": {
"type": "data_view_spec",
"index_pattern": "kibana_sample_data_logs",
"time_field": "timestamp"
}
}
],
"styling": {
"fitting": { "type": "linear" }
}
}
moving_averageover theaverageofmachine.ramsmooths out spikes and produces a trend line.decimals: 0keeps the byte labels clean.breakdown_bysplits the chart into one line per host, limited to the top 4 values ofhost.keyword.rank_by: "alphabetical"is required here becausemoving_averageis a pipeline aggregation and cannot be used to sort breakdown buckets.
curl -X POST "${KIBANA_URL}/api/visualizations" \
-H "Authorization: ApiKey ${API_KEY}" \
-H "kbn-xsrf: true" \
-H "Content-Type: application/json" \
-d '{
"type": "xy",
"title": "Average RAM per host",
"filters": [],
"query": { "expression": "" },
"legend": { "visibility": "visible", "placement": "outside", "position": "bottom" },
"axis": {},
"layers": [
{
"type": "line",
"x": {
"operation": "date_histogram",
"field": "timestamp",
"suggested_interval": "1h"
},
"y": [
{
"operation": "moving_average",
"of": {
"operation": "average",
"field": "machine.ram",
"format": { "type": "bytes", "decimals": 0 },
"filter": { "expression": "" }
},
"label": "Moving average of RAM",
"format": { "type": "bytes", "decimals": 0 },
"filter": { "expression": "" },
"color": {
"type": "static",
"color": "#6092c0"
}
}
],
"breakdown_by": {
"operation": "terms",
"fields": ["host.keyword"],
"limit": 4,
"rank_by": { "type": "alphabetical", "direction": "asc" }
},
"data_source": {
"type": "data_view_spec",
"index_pattern": "kibana_sample_data_logs",
"time_field": "timestamp"
}
}
],
"styling": {
"fitting": { "type": "linear" }
}
}'
moving_averageover theaverageofmachine.ramsmooths out spikes and produces a trend line.decimals: 0keeps the byte labels clean.breakdown_bysplits the chart into one line per host, limited to the top 4 values ofhost.keyword.rank_by: "alphabetical"is required here becausemoving_averageis a pipeline aggregation and cannot be used to sort breakdown buckets.
For more information, refer to the Visualizations API.
- Unique IPs over time
- Visualize the number of unique client IPs throughout the day to identify traffic patterns and peak usage periods:
- Drag
timestampto the Horizontal axis and set Functions toDate histogramwith Minimum interval set toHour. - Drag
clientipto the Vertical axis and set the following settings:- Functions:
Unique count - Value format:
Number - Decimals:
0
- Functions:
- In the Visual options, set Missing values to
Linearto connect gaps in the line. - Save your chart.

Create this chart using the API
Send the following request to create a line chart that plots the unique count of client IPs over time, with linear interpolation for missing values.
POST kbn://api/visualizations
{
"type": "xy",
"title": "Unique IPs over time",
"filters": [],
"query": { "expression": "" },
"legend": { "visibility": "auto" },
"axis": {},
"layers": [
{
"type": "line",
"x": {
"operation": "date_histogram",
"field": "timestamp",
"suggested_interval": "1h"
},
"y": [
{
"operation": "unique_count",
"field": "clientip",
"label": "Unique IPs",
"format": {
"type": "number",
"decimals": 0
},
"filter": { "expression": "" }
}
],
"data_source": {
"type": "data_view_spec",
"index_pattern": "kibana_sample_data_logs",
"time_field": "timestamp"
}
}
],
"styling": {
"fitting": {
"type": "linear"
}
}
}
suggested_interval: "1h"sets the date histogram to bucket by hour.unique_countonclientipcounts distinct IP addresses per time bucket, tracking unique visitors rather than total requests.fitting.type: "linear"connects data points across empty buckets with a straight line instead of leaving gaps.
curl -X POST "${KIBANA_URL}/api/visualizations" \
-H "Authorization: ApiKey ${API_KEY}" \
-H "kbn-xsrf: true" \
-H "Content-Type: application/json" \
-d '{
"type": "xy",
"title": "Unique IPs over time",
"filters": [],
"query": { "expression": "" },
"legend": { "visibility": "auto" },
"axis": {},
"layers": [
{
"type": "line",
"x": {
"operation": "date_histogram",
"field": "timestamp",
"suggested_interval": "1h"
},
"y": [
{
"operation": "unique_count",
"field": "clientip",
"label": "Unique IPs",
"format": {
"type": "number",
"decimals": 0
},
"filter": { "expression": "" }
}
],
"data_source": {
"type": "data_view_spec",
"index_pattern": "kibana_sample_data_logs",
"time_field": "timestamp"
}
}
],
"styling": {
"fitting": {
"type": "linear"
}
}
}'
suggested_interval: "1h"sets the date histogram to bucket by hour.unique_countonclientipcounts distinct IP addresses per time bucket, tracking unique visitors rather than total requests.fitting.type: "linear"connects data points across empty buckets with a straight line instead of leaving gaps.
For more information, refer to the Visualizations API.