Skip to content

Performance

Benchmark Setup

All data was collected by running 100 consecutive HTTP GET requests with a JSON payload on a real ESP32 device against the public JSONPlaceholder /users endpoint. Both libraries were configured with default settings. The WiFi connection was already established before the benchmark started.


Results

Metric / Feature Standard (HTTPClient + ArduinoJson) ESP32-HTTP-Client Comparison
Heap allocation per request ~58.2 KB ~15 bytes ⬇ ~99.9% less RAM
Avg. RAM footprint 34.2% 24.3% ⬇ ~29% less overall
Minimum free heap 114.3 KB 128.6 KB ⬆ Safer headroom
Avg. execution time ~750 ms ~59 ms 🚀 ~12× faster
Code verbosity ~15 lines of boilerplate 1 fluent chain ⬇ Clean & maintainable
JSON parsing deserializeJson() Automatic, direct binding ⬆ No document allocation

Why is it so much faster?

HTTP Keep-Alive

ESP32HTTPClient enables HTTP/1.1 Keep-Alive by default via _http.setReuse(true). This allows the underlying TCP/TLS connection to be reused across multiple requests to the same server.

The standard approach typically closes and reopens the connection on every call, paying the full TLS handshake cost (~700–800 ms on a typical WiFi network) each time.

Zero-Copy Stream Parsing

Instead of calling http.getString() (which allocates the entire response in heap memory) and then passing it to deserializeJson() (which allocates a DynamicJsonDocument), this library:

  1. Obtains a raw Stream* pointer directly from the HTTPClient.
  2. Parses the JSON stream byte by byte through BufferedStreamReader.
  3. Writes matched values directly into your pre-declared C variables.

The full response body is never stored in memory. The total heap allocation for a typical response is ~15 bytes of internal state.

Chunked Transfer Encoding

Modern APIs commonly respond with Transfer-Encoding: chunked. The library's BufferedStreamReader automatically decodes chunked responses without requiring the full payload to be buffered first.


Memory Trade-offs & TLS Heap Lifecycle

Scenario Heap allocated during request RAM freed by end()
Plain HTTP connection (http://) ~15 bytes ~5–10 KB socket buffers
TLS without config (https:// default) Core default Core default
Configured TLS (setCACert, bundle, etc.) ~45 KB (mbedTLS buffers) ~45 KB (TLS context + record buffers)

On-Demand TLS Allocation

ESP32HTTPClient uses lazy on-demand allocation for secure connections. The internal secure client is not initialized during object construction. Sketches communicating solely over http:// incur zero TLS heap overhead.

When an https:// connection is established: 1. Initial Handshake: mbedTLS allocates internal SSL contexts and TX/RX record buffers (~45 KB). 2. Session Reuse (Keep-Alive): Subsequent requests to the same server reuse the already established TLS session, incurring no additional heap allocations and executing up to 12× faster. 3. Releasing TLS Memory: Calling client.end() terminates the TLS session, disconnects the socket, and frees the ~45 KB of mbedTLS buffers back to the heap. Subsequent calls will automatically initiate a fresh handshake when needed.

Call client.end() after a burst of requests if your sketch enters a long idle period:

// Burst of requests
for (int i = 0; i < 10; i++) {
    client.get("/data").getBody("v", &val);
    // ... process val
}

client.end(); // free ~45KB of TLS buffers
delay(60 * 1000); // sleep for 1 minute

Benchmark Source

The full benchmark sketches and comparison scripts are in the bench/ directory of the repository.