Getting Started with Flood.io: Your First Load Test

Getting Started with Flood.io: Your First Load Test

Getting a load test running on Flood takes less than 30 minutes if you have a JMeter plan ready. If you don't, this guide walks you through creating one. By the end you'll have run an actual flood and know how to read the results.

Account Setup

Go to flood.io and create an account. The free tier gives you a limited number of node hours per month — enough to run small tests and validate your scripts before committing to a paid plan.

After creating an account, you'll land on the dashboard. Two things to do immediately:

  1. Verify your email — required before you can launch a flood
  2. Check your node hour balance — visible in the top navigation; free tier allocates a fixed monthly allowance

No credit card required for the free tier.

Creating a JMeter Test Plan

If you already have a .jmx file, skip to the upload section. If not, here's a minimal JMeter plan that tests a web application — create it in JMeter GUI or write it by hand.

Save this as my-load-test.jmx:

<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5">
  <hashTree>
    <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Basic Load Test">
      <boolProp name="TestPlan.functional_mode">false</boolProp>
      <stringProp name="TestPlan.user_define_classpath"></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Users">
        <intProp name="ThreadGroup.num_threads">10</intProp>
        <intProp name="ThreadGroup.ramp_time">30</intProp>
        <longProp name="ThreadGroup.duration">300</longProp>
        <boolProp name="ThreadGroup.scheduler">true</boolProp>
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
      </ThreadGroup>
      <hashTree>
        <ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Defaults">
          <stringProp name="HTTPSampler.domain">your-app.example.com</stringProp>
          <stringProp name="HTTPSampler.protocol">https</stringProp>
          <intProp name="HTTPSampler.port">443</intProp>
        </ConfigTestElement>
        <hashTree/>
        <CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="Cookie Manager">
          <boolProp name="CookieManager.clearEachIteration">true</boolProp>
        </CookieManager>
        <hashTree/>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Homepage">
          <stringProp name="HTTPSampler.path">/</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
        </HTTPSamplerProxy>
        <hashTree>
          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Status 200">
            <collectionProp name="Asserion.test_strings">
              <stringProp name="49586">200</stringProp>
            </collectionProp>
            <intProp name="Assertion.test_type">8</intProp>
            <stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
          </ResponseAssertion>
        </hashTree>
        <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Products API">
          <stringProp name="HTTPSampler.path">/api/products</stringProp>
          <stringProp name="HTTPSampler.method">GET</stringProp>
          <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
        </HTTPSamplerProxy>
        <hashTree>
          <ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Status 200">
            <collectionProp name="Asserion.test_strings">
              <stringProp name="49586">200</stringProp>
            </collectionProp>
            <intProp name="Assertion.test_type">8</intProp>
            <stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
          </ResponseAssertion>
        </hashTree>
      </hashTree>
    </hashTree>
  </jmeterTestPlan>

This plan creates 10 threads (virtual users), ramps up over 30 seconds, and runs for 5 minutes hitting two endpoints.

Important: the thread count in your .jmx is a per-node baseline. When Flood runs this across multiple nodes, it multiplies. 10 threads × 5 nodes = 50 concurrent users. You can also override thread counts from the Flood UI.

Uploading Your Test Plan

From the Flood dashboard, click New Flood (or the + button, depending on UI version).

You'll see a file upload area. Drag your .jmx file in, or click to browse. Flood accepts:

  • .jmx files for JMeter
  • .scala or .zip files for Gatling
  • .ts or .js files for Flood Element

If your JMeter test uses external files (CSV data files, JARs for custom samplers, etc.), package them with your .jmx in a .zip. The directory structure inside the zip matters — reference files relative to the script's location.

For example, if your .jmx references testdata/users.csv:

my-test.zip
├── my-load-test.jmx
└── testdata/
    └── users.csv

After upload, Flood parses the file and shows detected transaction names. Verify these match what you expect — if you see generic names like "HTTP Request," your JMeter samplers aren't named, which makes results harder to read.

Configuring Your Grid

After uploading, configure the flood parameters:

Grid Selection

Flood Grid (hosted): Choose a region. For your first test, pick the region closest to your application or closest to where your real users are. US-East-1, EU-West-1, and AP-Southeast-1 are available on most plans.

Custom grid: If you've connected your AWS or GCP account, your private grids appear here. Skip this for now — it requires additional setup documented separately.

Node Configuration

  • Nodes: Number of concurrent nodes. Start with 1-2 for your first test to validate the script works. Scale up once you've confirmed the script runs cleanly.
  • Instance type: Standard instances work for most tests. High-memory instances matter if you're running browser-based tests (Flood Element) or JMeter tests with very high thread counts.

Load Profile

Set how virtual users are generated:

  • Duration: Total test duration in minutes. 5-10 minutes is enough for a first run.
  • Ramp-up: Time to reach peak users. 10-30 seconds for initial validation; longer ramps for production-like tests.
  • Users: Total concurrent users across all nodes. If your .jmx has 10 threads and you set 50 users in Flood, Flood distributes 50 users across your nodes (not 50 + 10).

For your first test: 1 node, 10 users, 5 minute duration, 30 second ramp-up.

Advanced Options

Override hosts: Redirect traffic to a different hostname without modifying your .jmx. Useful for pointing a production test script at staging.

JMeter properties: Pass JMeter properties that your test reads with ${__P(propertyName)}. This lets you parameterize things like thread counts and URLs at runtime rather than baking them into the .jmx.

Example — add this to JMeter properties:

target_host=staging.example.com
think_time=1000

Then reference in your .jmx:

${__P(target_host,localhost)}

Launching the Flood

Click Launch Flood. Flood queues the request, provisions nodes (takes 1-3 minutes), and starts the test.

You'll see the flood status change from queued → provisioning → executing. During provisioning, nothing is hitting your application yet.

Once executing, the real-time dashboard populates.

Reading the Results Dashboard

The results dashboard has several panels:

Real-Time Throughput

The top chart shows requests per second over time. You're looking for:

  • A rising curve during ramp-up (expected)
  • Plateau during sustained load (expected)
  • Dips or sudden drops (unexpected — usually means errors or your app is struggling)

If you see throughput plateau well below your target user count, your application is likely queuing or dropping requests.

Response Time Distribution

Shows mean, 95th percentile, and 99th percentile response times. The gap between mean and 95th matters more than the mean alone. A mean of 200ms with a 95th of 3000ms means 5% of your users are having a terrible experience.

Watch for the 95th percentile creeping up as load increases — this is the typical sign of a performance bottleneck.

Error Rate

Shows the percentage of failed requests. Under normal load this should be near zero. A small error rate (< 0.1%) is often acceptable depending on your SLAs. Anything above 1% under sustained load needs investigation.

Click the Errors tab to see error breakdown by type:

  • HTTP 5xx errors indicate server-side failures
  • Connection timeouts indicate network or server overload
  • HTTP 4xx errors often indicate test script problems (wrong URLs, missing auth headers)

Transaction Breakdown

Each named transaction in your JMeter plan appears separately. This lets you identify which specific endpoint is slow. If your homepage is 200ms but your checkout endpoint is 4000ms, the transaction breakdown shows that clearly.

Concurrent Users

Confirms virtual user ramp-up happened as configured. If you asked for 100 users and the chart shows you never got above 60, something prevented users from being created — often a high error rate early in the test causing JMeter to abort user threads.

After the Flood

When the test completes, the dashboard switches from real-time to the final results view. Key things to do:

Export results: Download raw data as CSV for analysis in Excel/Pandas/Grafana. The export includes per-second request rates, response times, and error counts.

Review the timeline: Look for when response times started degrading relative to user count. That inflection point is your current capacity limit.

Check the logs: Flood captures JMeter output. If your test had errors, the logs often explain why — missing files, connection refused, authentication failures.

Compare floods: After running multiple tests, the Flood dashboard lets you overlay results to compare before/after a deployment or configuration change.

Common First-Test Problems

Flood stays in "queued" for more than 5 minutes: Usually a node provisioning issue on Flood's side. Check status.flood.io. If the platform is healthy, try launching with one node in a different region.

All requests fail immediately: Check if your application is reachable from Flood's IP ranges. If you have IP whitelisting, Flood publishes its IP ranges — you'll need to allow them.

Thread count doesn't match what you configured: Flood overrides .jmx thread groups with its own user count settings. Your .jmx thread count is ignored unless you explicitly configure Flood to respect it.

Results show 0 transactions: Your .jmx has samplers but they're not generating any HTTP requests. Usually caused by using a View Results Tree listener that prevents samples from being processed in non-GUI mode. Remove GUI-only listeners from your .jmx before uploading.

CSV data file errors: Flood expects CSV files to be in the zip alongside the .jmx. Check that paths in JMeter's CSV Dataset Config match the zip structure exactly — paths are case-sensitive.

What to Test Next

Once your first flood completes successfully, increase load gradually:

  1. Run at 2× your baseline user count — verify response times are still acceptable
  2. Run a sustained test at peak expected load — 30-60 minutes at production levels
  3. Run a spike test — jump from 0 to peak load instantly, see how fast your app recovers
  4. Add geographic distribution — split the same load across two regions

Each test answers a different question about your application's behavior under load.

Read more

Start now free