Observability is useful only when it remains usable as an application grows. A dashboard that works well with five resources can become difficult to operate when a distributed application contains dozens or hundreds of resources, logs, traces, metrics, health checks, and changing service states.

.NET Aspire includes a developer dashboard for observing resources and telemetry during application development. Aspire 13.5 introduced improvements around dashboard filtering, reconnection behavior, health-check handling, and telemetry-related scenarios.

That makes an important engineering question worth testing: How does the Aspire dashboard behave when the amount of application telemetry increases significantly?

Rather than assuming that a dashboard feature scales well, developers can build a controlled workload and measure usability, resource consumption, connection behavior, and telemetry visibility.

Why Dashboard Scale Matters

A distributed application can generate many observability events.

Consider an application with:

API
 |
 +-- Authentication
 +-- Orders
 +-- Payments
 +-- Notifications
 |
 +-- PostgreSQL
 +-- Redis
 +-- Message Broker
 +-- Background Workers

Each component can produce:

As the number of resources increases, the dashboard has more information to display and process.

The challenge is not simply collecting telemetry. The dashboard must also help developers find the information they need.

What Should Be Benchmarked?

A dashboard benchmark should measure more than raw CPU or memory usage.

Useful dimensions include:

AreaWhat to Measure
StartupTime until dashboard is usable
Resource discoveryTime to display resources
FilteringResponsiveness when filtering
LogsLoading and rendering behavior
TracesTrace query responsiveness
MetricsChart rendering behavior
Health checksState update behavior
ReconnectionRecovery after connection interruption
MemoryDashboard process/resource usage
CPUResource usage during telemetry activity

The exact measurements should be collected from an actual test environment.

Do not present generic values as universal performance benchmarks.

Create a Controlled Aspire Application

Start with a small baseline.

var builder = DistributedApplication.CreateBuilder(args);

builder.AddProject<Projects.Api>("api");

builder.AddProject<Projects.Worker>("worker");

builder.AddRedis("cache");

builder.AddPostgres("postgres");

builder.Build().Run();

This gives you a starting point.

Then gradually increase the number of resources.

For example:

Test A: 5 resources
Test B: 25 resources
Test C: 50 resources
Test D: 100 resources

The exact scale should be selected based on the workload you want to investigate.

Generate Realistic Telemetry

Simply creating many resources is not enough.

The benchmark should generate telemetry that resembles real application activity.

For example:

public async Task ProcessRequestAsync()
{
    using var activity = ActivitySource
        .StartActivity("ProcessOrder");

    logger.LogInformation(
        "Processing order {OrderId}",
        orderId);

    await ProcessDatabaseOperationAsync();
    await ProcessNotificationAsync();
}

The goal is to create realistic combinations of:

Avoid generating artificial telemetry at an unrealistic rate unless the purpose of the test is specifically to determine a stress limit.

Establish a Baseline

Before testing large workloads, capture the dashboard's normal behavior.

Record:

Resource count
Telemetry rate
Dashboard startup time
Memory usage
CPU usage
Filter response
Log loading behavior
Trace loading behavior

For example:

TestResourcesTelemetry RateResult
Baseline5ControlledRecord
Medium25ControlledRecord
Large50ControlledRecord
Stress100+ControlledRecord

The table should contain actual measurements from your environment.

Testing Resource Filtering

Filtering becomes more important as the resource list grows.

Suppose the dashboard contains:

api-orders
api-users
api-payments
worker-orders
worker-notifications
postgres
redis
messagebus
...

A useful benchmark should test whether filtering remains responsive as the number of resources increases.

Measure:

Type filter
     |
     v
Search / Filter
     |
     v
Visible Resources
     |
     v
Response Time

The important metric is not simply whether filtering works, but whether the user can interact with it comfortably under a large resource set.

Testing Logs Under Load

Logs can become one of the largest telemetry streams.

Generate representative structured logs:

logger.LogInformation(
    "Order {OrderId} processed for customer {CustomerId}",
    orderId,
    customerId);

Then measure:

A benchmark should avoid generating sensitive production data.

Use synthetic identifiers and controlled test content.

Testing Distributed Traces

Distributed tracing becomes valuable as applications become more complex.

A single request might produce:

HTTP Request
   |
   +-- Authentication
   |
   +-- Order Service
          |
          +-- PostgreSQL
          |
          +-- Redis
          |
          +-- Notification Worker

The dashboard needs to make this relationship understandable.

A useful test should therefore measure trace discovery and inspection rather than simply counting trace records.

Health Check Behavior

Health checks are another important part of the dashboard.

A service might expose:

API
 |
 +-- Database Health
 +-- Cache Health
 +-- Message Broker Health

Test transitions such as:

Healthy
  |
  v
Dependency Failure
  |
  v
Unhealthy
  |
  v
Dependency Recovered
  |
  v
Healthy

Measure how quickly the dashboard reflects meaningful state changes.

The purpose is to test observability behavior, not to claim a universal health-check propagation time.

Testing Reconnection Behavior

Distributed development environments can experience temporary connectivity problems.

A useful experiment deliberately interrupts the dashboard's connection and observes what happens.

Connected
   |
   v
Connection Interrupted
   |
   v
Dashboard State
   |
   v
Connection Restored
   |
   v
Telemetry Recovery

Record:

This is particularly useful when developing over remote or unstable environments.

Measuring Memory Usage

Memory should be measured throughout the test rather than only at startup.

A useful test pattern is:

Start Dashboard
     |
     v
Load Resources
     |
     v
Generate Telemetry
     |
     v
Browse Logs
     |
     v
Browse Traces
     |
     v
Apply Filters
     |
     v
Measure Memory

This helps distinguish startup allocation from workload-related growth.

A single memory measurement cannot tell you whether memory usage remains stable over time.

Testing CPU Usage

CPU measurements should be collected while the dashboard is performing specific activities.

For example:

Idle
 |
 +-- Resource browsing
 |
 +-- Log filtering
 |
 +-- Trace inspection
 |
 +-- High telemetry activity

This creates a more useful profile than simply recording average CPU utilization for the entire test.

Large Workload Testing

A meaningful stress test should increase workload dimensions gradually.

For example:

Phase 1
10 resources

Phase 2
25 resources

Phase 3
50 resources

Phase 4
100 resources

Phase 5
Increase telemetry volume

This makes it easier to identify the point at which behavior changes significantly.

Do not jump directly from five resources to an arbitrarily large number and call the resulting observation a scalability limit.

A true scalability limit requires a controlled experiment and clearly defined acceptance criteria.

Separating Dashboard and Application Performance

One important benchmarking mistake is confusing dashboard overhead with application overhead.

The application may be performing normally while the dashboard is processing large amounts of telemetry.

Therefore, monitor both:

Application
  |
  +-- CPU
  +-- Memory
  +-- Request Latency

Dashboard
  |
  +-- CPU
  +-- Memory
  +-- Rendering
  +-- Telemetry Processing

This separation makes the results easier to interpret.

Example Benchmark Record

A useful benchmark record could contain:

{
  "resourceCount": 50,
  "telemetryProfile": "medium",
  "scenario": "trace-inspection",
  "dashboardMemoryMb": 0,
  "dashboardCpuPercent": 0,
  "filterResponseMs": 0,
  "reconnection": "pass"
}

The zero values here are placeholders.

The benchmark should populate them from actual measurements rather than invented numbers.

Common Mistakes

Measuring Only Startup

A dashboard may start quickly but behave differently after processing a large amount of telemetry.

Generating Unrealistic Telemetry

An artificial event generator can create a workload that has little relationship to actual application behavior.

Testing Only Resource Count

Ten resources producing huge telemetry volumes may be more demanding than one hundred mostly idle resources.

Ignoring Browser Performance

The dashboard is a user interface. Browser rendering and client-side processing can affect perceived performance.

Using One Machine

A benchmark performed on a single development machine does not automatically represent another developer workstation or CI environment.

Treating One Test as a Universal Limit

The results depend on resource count, telemetry rate, machine capacity, browser, application architecture, and environment.

Troubleshooting

Dashboard Becomes Slow

Determine which activity causes the slowdown.

Test separately:

This helps isolate the source.

Memory Keeps Increasing

Run a longer test and monitor memory over time.

Also check whether the workload continuously increases the amount of retained telemetry.

A continuously growing workload is different from a fixed dataset being repeatedly inspected.

Telemetry Disappears After Reconnection

Check whether the issue is with:

Do not assume the dashboard is the source without isolating the layers.

Health Status Is Unexpected

Verify the underlying health-check endpoint independently.

If the application reports an incorrect health state, dashboard behavior may simply be reflecting the source data.

Best Practices for Aspire Dashboard Benchmarking

  1. Establish a small baseline.

  2. Increase resource count gradually.

  3. Control telemetry generation.

  4. Measure logs, traces, metrics, and health checks separately.

  5. Test filtering with realistic resource counts.

  6. Test reconnection behavior explicitly.

  7. Monitor CPU and memory over time.

  8. Record browser and machine characteristics.

  9. Separate application resource usage from dashboard usage.

  10. Repeat important measurements.

  11. Keep benchmark data consistent.

  12. Avoid publishing unsupported performance limits.

Advantages and Disadvantages

Advantages

Disadvantages

A Practical Test Matrix

A team evaluating Aspire dashboard behavior can use a matrix like this:

ScenarioResourcesTelemetryLogsTracesHealth ChecksReconnect
BaselineSmallLowYesYesYesYes
MediumMediumMediumYesYesYesYes
LargeLargeHighYesYesYesYes
StressLargeVery HighYesYesYesYes

The exact resource counts and telemetry rates should be chosen based on the application's expected operating profile.

Conclusion

.NET Aspire's dashboard provides developers with a convenient way to observe distributed applications, but observability itself needs to be tested when applications grow. Aspire 13.5 includes improvements around dashboard behavior and telemetry workflows, making it reasonable to evaluate how those capabilities behave under controlled larger workloads.

The most useful benchmark does not attempt to produce one universal "maximum number of services" or "maximum telemetry rate." Instead, it measures how resource discovery, filtering, logs, traces, health checks, reconnection, CPU, and memory behave as workload complexity increases.

For teams using Aspire at scale, this type of testing can expose problems before the dashboard becomes a bottleneck in daily development. More importantly, it encourages a broader observability mindset: telemetry is not useful merely because it exists; developers must still be able to find, interpret, and act on it when the application becomes busy.