> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loadforge.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Load Test Shapes - Ramp, Spike & Step Patterns

> How to customize the user load shape of a test with ramp-up, spike, step, and custom patterns in LoadForge.

**Custom Shapes** allow you to precisely control how users ramp up and down during your tests. This is useful for advanced scenarios where a fixed or linear user load is insufficient.

<Note>
  **Tip:** The default LoadForge test settings work well for most use cases. Custom Shapes should be used when you have a **specific load profile requirement**.
</Note>

## Basic Custom Shape

This shape gradually increases users in blocks of **100** over a **10-minute test duration**:

```python theme={null}
from locust import HttpUser, task, between
from locust import LoadTestShape

class QuickstartUser(HttpUser):
    wait_time = between(5, 9)

    @task(1)
    def index_page(self):
        self.client.get("/")

class MyCustomShape(LoadTestShape):
    time_limit = 600
    spawn_rate = 20

    def tick(self):
        run_time = self.get_run_time()

        if run_time < self.time_limit:
            user_count = round(run_time, -2)  # Round to nearest 100
            return (user_count, self.spawn_rate)
        return None
```

## Double Wave Custom Shape

Simulates **two peaks** of user traffic, useful for scenarios like meal times or daily traffic fluctuations.

```python theme={null}
import math
from locust import HttpUser, task, between
from locust import LoadTestShape

class QuickstartUser(HttpUser):
    wait_time = between(5, 9)

    @task(1)
    def index_page(self):
        self.client.get("/")

class DoubleWave(LoadTestShape):
    min_users = 20
    peak_one_users = 60
    peak_two_users = 40
    time_limit = 300

    def tick(self):
        run_time = round(self.get_run_time())

        if run_time < self.time_limit:
            user_count = (
                (self.peak_one_users - self.min_users) * math.exp(-(((run_time / (self.time_limit / 10 * 2 / 3)) - 5) ** 2))
                + (self.peak_two_users - self.min_users) * math.exp(-(((run_time / (self.time_limit / 10 * 2 / 3)) - 10) ** 2))
                + self.min_users
            )
            return (round(user_count), round(user_count))
        return None
```

## Stages Custom Shape

Define exact **user counts at specific times**.

```python theme={null}
from locust import HttpUser, task, between
from locust import LoadTestShape

class QuickstartUser(HttpUser):
    wait_time = between(5, 9)

    @task(1)
    def index_page(self):
        self.client.get("/")

class StagesShape(LoadTestShape):
    stages = [
        {"duration": 60, "users": 10, "spawn_rate": 10},
        {"duration": 100, "users": 50, "spawn_rate": 10},
        {"duration": 180, "users": 100, "spawn_rate": 10},
        {"duration": 220, "users": 30, "spawn_rate": 10},
        {"duration": 240, "users": 1, "spawn_rate": 1},
    ]

    def tick(self):
        run_time = self.get_run_time()
        for stage in self.stages:
            if run_time < stage["duration"]:
                return (stage["users"], stage["spawn_rate"])
        return None
```

## Step Load Shape

Increases users in steps and waits at each step before increasing further.

```python theme={null}
import math
from locust import HttpUser, task, between
from locust import LoadTestShape

class QuickstartUser(HttpUser):
    wait_time = between(5, 9)

    @task(1)
    def index_page(self):
        self.client.get("/")

class StepLoadShape(LoadTestShape):
    step_time = 30
    step_load = 10
    spawn_rate = 10
    time_limit = 600

    def tick(self):
        run_time = self.get_run_time()
        if run_time > self.time_limit:
            return None
        current_step = math.floor(run_time / self.step_time) + 1
        return (current_step * self.step_load, self.spawn_rate)
```

## When to Use Custom Shapes

Consider using a **custom shape** if:

* You need **gradual user ramp-ups** rather than sudden traffic spikes.
* You are **simulating real-world traffic patterns**, such as lunch-hour surges.
* Your application has **specific scalability concerns** requiring controlled increases.

Otherwise, the **default LoadForge load shape** is recommended for general testing.

By implementing **Custom Shapes**, you can fine-tune your **LoadForge tests** to reflect **realistic user behavior and performance bottlenecks** more accurately.
