Reduce Grafana Cloud Performance Testing costs
Grafana Cloud k6 subscriptions are billed based on usage in Virtual User Hours (VU hours, or VUH), the number of static IP addresses, and the metrics your tests generate. This guide discusses how to review and reduce each of these costs.
Review your Virtual User Hour usage
You can review usage on the Billing and Usage dashboard on the k6 Virtual User Hours (VUH) panel. You can also review usage reports to understand how your different projects, teams, and contributors are impacting your overall usage.
Before running tests, use the Grafana Cloud k6 calculator to estimate VUH consumption and costs for different test configurations. This helps you plan your testing budget and optimize test design.
Reduce your Virtual User Hour costs
Test locally
To save on VU hours, prototype and debug scripts on a local machine. After you have the correct logic, increase the load and duration to the desired levels, then run the script with k6 cloud run for managed execution, visualization, and storage.
Start with a smoke test
Start with a smoke test. Before running larger tests, validate that your performance testing script works as expected and that your system performs well with a small number of users.
After you know that the script works and the system responds correctly to minimal load, you can move on to average-load tests. From there, you can progress to more complex load patterns.
Refer to Load test types to learn more about the different types of performance tests.
Set project limits and quotas
When creating performance tests in Grafana Cloud k6, you have to define a few parameters, such as virtual users (VUs), and test duration. After a test is executed, you also have the number of virtual user hours (VUH) used by a test run. Each Grafana Cloud subscription has different limits for those parameters.
To help your team manage your account limits, and avoid having unexpected charges at the end of the billing cycle, you can set limits and quotas to individual projects.
Use Grafana Cloud Synthetic Monitoring
The Synthetic Monitoring tool supports k6 scripted checks and k6 browser checks, which can reduce VUH usage costs. To learn more about how Synthetic Monitoring is billed and the supported k6 Options for scripted checks, refer to the guides below.
- Understand your Synthetic Monitoring invoice
- Supported k6 Options for k6 browser checks
- Supported k6 Options for k6 scripted checks
Remove unused static IP addresses
Static IP addresses can provide additional security and convenience when running performance tests. Each static IP address incurs a monthly charge, which is added to your Grafana Cloud subscription. To reduce costs, review your performance tests to make sure they’re still using the IP addresses assigned to your Grafana Cloud account and delete any unused static IP addresses.
How Grafana Cloud bills your k6 metrics
Your metrics cost depends on cardinality—how many distinct time series a test creates—not on how many virtual users you run. A 1,000-VU load test can be cheap. A 1-VU test with an unbounded loop can be expensive.
Grafana Cloud bills these metrics by active series—the distinct time series your tests keep alive in a billing period—the same way it bills any other Grafana Cloud metrics.
Billing is based on the P95 of your monthly active series, not a one-off spike, together with the data points per minute (DPM) your tests produce, so a more frequent sample rate raises the billable amount. For exactly how Grafana Cloud calculates the bill, refer to Billing calculations.
The pattern holds across test sizes. A well-scoped 1,000-VU soak with about 25 series stays cheap, while a 1-VU test with an unbounded high-cardinality loop can produce thousands of series or more and cost substantially more. As a safeguard, k6 enforces a per-run cardinality limit that scales with your test, capped at 200,000 active series, and stops a run that crosses it before it runs away. Cardinality drives the bill, so the rest of this guide is about seeing and reducing it.
Runaway tests stop automatically
k6 protects you from a runaway bill. Each run gets a cardinality limit sized to the test, capped at 200,000 active series; if a run crosses its limit, k6 stops it as a precaution rather than letting its cardinality keep climbing.
If your tests hit this limit, it’s a sign to reduce their cardinality with the techniques in this guide. If you have a legitimate need for more series, contact support.
See your metrics footprint
Before you change anything, find out what your tests generate.
Each test run reports how many time series it produced, so start with your highest-cardinality and most frequent tests. Running a test to measure it is safe. Because your bill is based on the 95th percentile of your monthly active series, Grafana Cloud forgives the highest-usage part of each billing period—roughly the top 36 hours—so a one-off discovery run barely moves your bill. A test has to run at high cardinality for a sustained part of the month before it affects billing. This protection is about how long high cardinality lasts, not how high it goes: it’s the recurring, scheduled, and long-running tests that keep series alive over time that drive your bill, not a single run.
Your usage dashboard shows active series and data points over time, so you can read your sustained, P95 level. Grafana Cloud’s cardinality management dashboards also show how your series and labels break down, so you can spot the worst offenders. To see how your cardinality has trended over time, refer to Historical cardinality in the Cost Management pages.
Scheduled and CI runs dominate sustained active-series counts, so look at your heaviest recurring tests first. If you can’t say roughly what a test costs before you run it, start here.
Reduce your metrics cost
You reduce cost by generating fewer, more meaningful series. The following techniques are in rough order of impact.
Drop metrics you don’t use
k6 emits a set of built-in metrics by default, and many tests never use most of them. Dropping the ones you don’t need is usually the biggest single cut.
Set drop_metrics in your script’s options.cloud block to a list of metric names to drop at ingestion. You can’t drop the vus metric.
export const options = {
cloud: {
drop_metrics: ['http_req_tls_handshaking', 'http_req_waiting', 'http_req_connecting'],
},
};Refer to Cloud options.
Reduce load zones and instances
Cardinality also scales with how many load-generator instances your test uses, independent of anything in your script. Grafana Cloud k6 runs at least one instance per load zone, and adds more instances as the virtual user count within a zone grows. Each instance reports its own metric series, so a test spread across several load zones, or split across multiple instances in one zone, produces a multiple of the series that the same test run from a single instance would.
If your test doesn’t need geographic distribution, run it from a single load zone. Grafana Cloud calculates the VU-per-instance threshold dynamically for each run, so check how many instances your own test actually used: query the vus or load_generator_cpu_percent metric grouped by instance_id (refer to Metrics in the Cloud REST API reference) and count the distinct values. This lever matters most for scheduled and recurring tests: instance-driven cardinality repeats every run and compounds over the billing period the same way sample rate and URL cardinality do.
Group dynamic URLs
k6 tags each HTTP request with a name tag that defaults to the URL, so requests like /posts/1 and /posts/2 each become a separate series. Set an explicit name tag so they collapse into one.
http.get(`http://example.com/posts/${id}`, { tags: { name: 'PostsItemURL' } });The http.url template wrapper normalizes the name for you.
http.get(http.url`http://example.com/posts/${id}`);Refer to URL grouping.
Normalize browser navigations
Browser tests hit the same problem when navigations contain changing IDs, which also triggers the “too many time series” error. Use page.on('metric') with regular expression matchers to give varying URLs one shared name.
const page = await browser.newPage();
page.on('metric', (metric) => {
metric.tag({
name: 'test',
matches: [
{ url: /^https:\/\/test\.k6\.io\/\?q=[0-9a-z]+$/, method: 'GET' },
],
});
});Refer to Prevent the “too many time series” error.
Adjust the sample rate
You can set how often k6 samples metrics per organization. The default is every 12 seconds. A long test, for example a one-hour soak, doesn’t need frequent sampling, so a coarser rate cuts the data points it generates with no real loss of insight. To change your organization’s sample rate, contact support.
Verify the impact
After you apply these changes, run the test again and check its series count. A lower count means a lower bill. Compare it against the previous run to confirm the reduction.
Quick checklist before a large test run
Run through these checks before a large or frequent test to keep its metrics cost down.
- Check the series count of this test’s last run.
- Drop built-in metrics you don’t use.
- Use only as many load zones and instances as the test needs.
- Keep high-cardinality values such as IDs, timestamps, and unique URLs out of tags.
- Group dynamic URLs so they collapse into one series.
- In browser tests, normalize navigations that contain changing IDs.
- Match the sample rate to the test length. The longer the test, the coarser the sampling.


