Using Grafana List Variables to Build Dynamic Dashboards Without Code Changes
Learn how Grafana list variables let you add dynamic filters to dashboards without editing queries. Build chained, hierarchical filters, avoid duplicates, and manage refresh modes for optimal performance.
05 Dec 2025, 21:05 UTC

Problem: Static Dashboards Lose Flexibility
When a team builds a Grafana dashboard that shows metrics for multiple regions, accounts, or services, the usual approach is to hard‑code each filter into the panel queries. Adding a new region or changing the scope then requires editing every query, redeploying the dashboard, and risking human error. This workflow is slow and brittle, especially in environments that change frequently.
The practical question for many engineers is: How can I let end‑users pick a region, account, or other dimension at runtime, without touching the SQL or PromQL in each panel?
Thesis: List Variables Turn a Static Dashboard into a Dynamic Tool
Grafana’s list variables provide a declarative way to expose dynamic filters. By defining a variable once, you can reference its value in any panel query, and the dashboard automatically updates when the user changes the selection. This eliminates repetitive edits, reduces risk, and keeps dashboards lightweight.
1. What List Variables Are and How They Work
A list variable is a named value that Grafana can inject into panel queries. The variable’s options come from one of three sources:
- Query – The variable runs a data‑source query and populates its options from the result set.
- Inline – You provide a comma‑separated list of values directly in the variable definition.
- Range – Grafana generates a numeric range (e.g., 1‑10) automatically.
When a panel query contains the variable syntax $var-name or ${var-name}, Grafana substitutes the currently selected value before sending the query to the data source. The substitution happens on the fly, so the panel refreshes instantly without a full dashboard reload.
2. Setting Up a List Variable
Below is a step‑by‑step guide to create a list variable that pulls available AWS regions from a CloudWatch data source. The same steps apply to any SQL, Prometheus, or Loki source.
- Navigate to Dashboard Settings → Variables and click Add Variable.
- Choose Type: List and give the variable a name, e.g.,
region. - Set Data source to your CloudWatch connection.
- In the Query field, enter a query that returns distinct region names:
SELECT DISTINCT region FROM aws_cloudwatch_metrics WHERE metric_name = 'CPUUtilization' - Under Refresh, pick a mode:
- On Dashboard Load – Query runs once when the dashboard opens.
- As You Type – Useful for large lists; the query runs each time the user types.
- Periodically – Set an interval (e.g., 5m) if the underlying data changes often.
- Optional: Add a Multi‑select toggle if you want users to pick multiple regions. Remember that multi‑select values join with commas in queries.
- Click Save and test by selecting a region from the drop‑down on the dashboard.
When you reference the variable in a panel query, use $region:
SELECT * FROM cpu_usage WHERE region = '$region'
Grafana replaces $region with the chosen value before executing the query.
3. Chaining Variables for Hierarchical Filters
Often you need a two‑level filter: first pick a region, then an availability zone within that region. Grafana supports chained variables where the child’s query references the parent variable.
- Create
regionas described above. - Add another variable,
az, set as Type: List and Data source to the same source. - In the
azquery, reference$region:SELECT DISTINCT az FROM aws_cloudwatch_metrics WHERE region = '$region' - Enable Refresh: On Dashboard Load for
azso it updates wheneverregionchanges.
Now, selecting a region automatically filters the availability zone list. Panels can reference both variables, e.g., WHERE region = '$region' AND az = '$az'.
4. Common Pitfalls and Performance Considerations
- Duplicate Entries – If the query returns duplicate values, Grafana will list them multiple times. Use
SELECT DISTINCTor transform the result set in the query. - Large Cardinality – Variables that return thousands of items can slow down the UI and the data source. Consider limiting the list with a
LIMITclause or switching to aRangevariable for numeric dimensions. - Periodic Refresh Overhead – Periodic refreshes fire every interval even if no user changes the selection. For high‑cardinality variables, set a longer interval or use On Dashboard Load instead.
- Multi‑select Query Syntax – When Multi‑select is enabled, Grafana passes the selected values as a comma‑separated string. Your query must handle that format, e.g.,
WHERE region IN ($region)for SQL.
Practical Example: Cloud Cost Dashboard
Suppose you want a dashboard that shows monthly cost per service, filtered by account and region. You can set up two list variables:
account– Query:SELECT DISTINCT account_id FROM billing WHERE date >= now() - interval '30 days'region– Query:SELECT DISTINCT region FROM billing WHERE account_id = '$account'
Panels use $account and $region in their queries. When a user selects a new account, the region list refreshes automatically, and all panels update instantly. No code changes are needed when new accounts or regions appear.
Actionable Take‑aways
- Start by defining a single list variable for the most frequently changed dimension.
- Use chained variables to build hierarchical filters; test the refresh behavior after each change.
- Always add
DISTINCTor appropriate filtering to avoid duplicate options. - Monitor the data source load when using Periodic refresh; adjust the interval or switch to On Dashboard Load if necessary.
- Document the variable definitions in a README or dashboard description so future maintainers understand the dynamic behavior.
With these steps, you can transform a static Grafana dashboard into a flexible, user‑driven tool that adapts to changing data without code churn.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.