# How to Create Charts and Graphs in Retool

- Tool: Retool
- Difficulty: Beginner
- Time required: 15-20 min
- Compatibility: Retool Cloud and Self-hosted
- Last updated: March 2026

## TL;DR

Drag a Chart component onto the canvas and set its Data source to {{ query1.data }}. Choose X and Y column names in the Inspector, select a chart type (Line, Bar, Pie, Scatter), and configure aggregation with the Group By option. Retool handles the visualization automatically — no Plotly JSON required for standard charts.

## Add Charts to Your Retool App in Under 5 Minutes

Retool's Chart component makes data visualization straightforward: connect it to a query, pick your columns, and choose a chart type. The built-in Series configuration handles the most common chart types — Line, Bar, Area, Scatter, Pie, Donut, and Histogram — without needing to write Plotly JSON.

The Chart component has two data modes: Simple (for queries that return data in the correct shape) and Group By (which lets Retool aggregate data by a category column without modifying the SQL). For advanced chart types like candlestick or gauge, see the custom charts tutorial.

This tutorial covers getting a chart working quickly with a query, adding multiple series, using Group By aggregation, and linking a filter input to update the chart dynamically.

## Before you start

- A Retool app with at least one query that returns tabular data
- Basic familiarity with the Retool Inspector panel
- A database with at least one date/category column and one numeric column

## Step-by-step guide

### 1. Drag a Chart component onto the canvas

From the component panel on the left, find 'Chart' and drag it onto your canvas. Resize it to a comfortable width — a full-width chart works well for trend lines, while half-width charts suit comparison bar charts. The component shows a placeholder with sample data until you connect a data source. Click the Chart to open its Inspector panel on the right.

**Expected result:** Chart component appears on canvas with placeholder visualization.

### 2. Connect the Chart to a query

In the Chart Inspector, find the 'Data source' field under the General section. Set it to {{ query1.data }} — replace 'query1' with your actual query name. The Chart expects the data to be an array of objects (which is the standard format Retool SQL queries return). Once connected, if Retool can detect numeric and date/string columns, it will attempt to auto-configure the chart. You may see a rough chart appear immediately.

```
// Example query returning chart-ready data:
// SELECT month, revenue, expenses FROM monthly_summary ORDER BY month;
// Access as: {{ monthlyData.data }}
```

**Expected result:** Chart shows a rough visualization using auto-detected columns from the connected query.

### 3. Configure X axis and Y axis series

In the Inspector, set the X axis to the column that should be on the horizontal axis — typically a date, month name, or category string. Click '+ Add series' to configure the Y axis. Set the 'Y column' to a numeric column like 'revenue'. Set the Series type to 'Line', 'Bar', 'Scatter', or 'Area'. Set a Label for the series (shown in the legend). Add a second series for a comparison metric: click '+ Add series' again and set Y column to 'expenses'. Both metrics will appear on the same chart.

```
// Chart Inspector configuration (pseudocode):
// X axis column: 'month'
// Series 1 — Y column: 'revenue', Type: Line, Label: 'Revenue'
// Series 2 — Y column: 'expenses', Type: Line, Label: 'Expenses'
```

**Expected result:** Chart displays two labeled line series for revenue and expenses over the X-axis months.

### 4. Use Group By to aggregate data in the chart

If your query returns raw transaction rows (not pre-aggregated), enable Group By in the Chart Inspector. Set 'Group by' to a category column (e.g., 'product_category'). Set 'Aggregate' to SUM or COUNT. Set the Y column to 'amount'. Retool will aggregate all rows with the same category value and display one bar per category — no SQL GROUP BY required. This is ideal for ad-hoc exploration when you don't want to modify the underlying query.

**Expected result:** Chart shows one aggregated bar per category without modifying the underlying SQL query.

### 5. Choose chart type and configure display options

In the Series configuration, change the Type dropdown to see all available types: Line, Bar, Area, Scatter, Pie, Donut, Histogram. For a Pie or Donut chart, only one series is used — set the 'Labels column' to a category column and 'Values column' to a numeric column. In the Axes section, set axis titles, number format (e.g., '$,.0f' for currency), and enable/disable gridlines. Under Colors, customize the series colors.

**Expected result:** Chart renders in the chosen type with formatted axis labels and custom colors.

### 6. Link a filter input to update the chart dynamically

Add a Select dropdown component above the chart. Populate it with options (e.g., '7 days', '30 days', '90 days') as static values. In your chart's underlying query, add a WHERE clause that references the dropdown: WHERE created_at >= NOW() - INTERVAL '{{ select1.value }}'. Enable 'Run when inputs change' on the query. Now when the user changes the dropdown, the query re-runs and the chart updates. You can also reference multiple filter components for multi-dimensional filtering.

```
-- Query with dynamic time filter
SELECT
  DATE_TRUNC('day', created_at) AS day,
  SUM(amount) AS revenue
FROM orders
WHERE created_at >= NOW() - INTERVAL {{ select1.value + ' days' }}
GROUP BY 1
ORDER BY 1;
```

**Expected result:** Changing the dropdown selection triggers the query and updates the chart for the new time range.

## Complete code example

File: `SQL Query: getChartData (multi-series)`

```sql
-- Multi-series chart query
-- Returns daily revenue, expenses, and profit for the selected period
-- Chart X axis: period
-- Series 1: revenue (Line)
-- Series 2: expenses (Line)
-- Series 3: profit (Bar)

SELECT
  DATE_TRUNC('day', date) AS period,
  SUM(revenue) AS revenue,
  SUM(expenses) AS expenses,
  SUM(revenue) - SUM(expenses) AS profit
FROM daily_financials
WHERE
  date >= {{ dateRangePicker1.value[0] ?? moment().subtract(30, 'days').toISOString() }}
  AND date <= {{ dateRangePicker1.value[1] ?? moment().toISOString() }}
  AND department = {{ select1.value === 'All' ? '%' : select1.value }}
GROUP BY 1
ORDER BY 1;
```

## Common mistakes

- **Setting Data source to {{ query1.data }} when query1 hasn't run yet, resulting in an empty chart** — undefined Fix: Ensure the query has 'Run on page load' enabled, or add a default Date Range Picker value so the query has parameters to run with on load.
- **Using a query that returns data in wide format (one column per metric) when the chart expects long format** — undefined Fix: The Chart component works best with long-format data (one row per data point). If your data is wide (columns for each date), use a Transformer to unpivot it before passing to the chart.
- **Adding too many series to one chart, making it unreadable** — undefined Fix: Limit to 3-5 series per chart. For more metrics, create multiple charts organized in a dashboard layout.

## Best practices

- Sort your query data by the X axis column (ORDER BY date) — unsorted data creates jagged line charts
- Limit the number of data points shown to Retool: 100-500 points renders quickly, 5,000+ points may slow the chart
- Use a Loading state indicator near the chart: a Spinner component with Visible set to {{ query1.isFetching }}
- For Pie charts, limit to 5-8 slices — too many slices make pie charts unreadable. Aggregate small values into an 'Other' category in SQL
- Set axis number formats to match your data: '$,.0f' for currency, '.1%' for percentages, ',.0f' for large integers
- Label each series clearly — 'Revenue' is more useful than 'Series 1' in the chart legend

## Frequently asked questions

### Why is my Retool chart showing blank or no data?

The most common causes are: (1) the query hasn't run yet — check the Debug Panel Queries tab to see its status, (2) the Data source expression evaluates to an empty array — confirm {{ query1.data }} is not an empty [], (3) the X or Y column names don't match the actual query column names — column names are case-sensitive.

### Can I display data from two different queries in one Retool chart?

Not directly — a Chart component has one Data source. To combine data from two queries, use a Transformer that merges the two result sets into a single array before passing it to the chart. For example, join query1.data and query2.data by a common key field using JavaScript reduce().

### How do I make a Retool chart show percentage values on the Y axis?

In the Chart Inspector's Y axis section, set the Tick format to '.0%' for whole-number percentages or '.1%' for one decimal place. Make sure your underlying data values are in decimal format (0.75 for 75%), not already in percentage format (75), or the formatting will multiply them by 100 again.

---

Source: https://www.rapidevelopers.com/retool-tutorial/how-to-create-charts-and-graphs-in-retool
© RapidDev — https://www.rapidevelopers.com/retool-tutorial/how-to-create-charts-and-graphs-in-retool
