DynamicJsonDocument is a JsonDocument that allocates its memory pool in the heap.

Because it calls malloc() and free(), DynamicJsonDocument is slightly slower than StaticJsonDocument.

DynamicJsonDocument allows storing much larger documents than StaticJsonDocument because it is not limited by the size of the stack.


Like JsonDocument, DynamicJsonDocument has value semantics: when you assign a DynamicJsonDocument to another, it makes a deep copy.

Here is an example:

DynamicJsonDocument doc2 = doc1;

Now, doc2 is a complete copy of doc1.

The capacity of the new document (doc2) matches the memory usage of the original (doc1). In other words, the memory footprint of the new document can be significantly lower than the original.

This feature is very handy when you return a JsonDocument from a function:

DynamicJsonDocument readConfigFile() {
    // ...
    DynamicJsonDocument doc(2048);
    deserializeJson(doc, file);
    return doc;

On the other hand, if you want to control the capacity of the new document, you must use two statements: one for the creation and one for the copy.

DynamicJsonDocument doc2(2048);
doc2 = doc1;

If this case, doc2 keeps its capacity of 2048 bytes, except if 2048 is not enough, in which case doc2 allocates a larger memory pool. This is the only situation where a JsonDocument reallocates its memory pool: only when copying from another JsonDocument.

Custom allocator

DynamicJsonDocument uses a default memory allocator that calls malloc() and free(). You can use other functions by passing a custom allocator class to BasicJsonDocument<T>. As an example, here is how DynamicJsonDocument is defined:

struct DefaultAllocator {
  void* allocate(size_t n) {
    return malloc(n);

  void deallocate(void* p) {

typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;

See BasicJsonDocument<T> for more information.

Member functions

  • as<T>() casts the root to the specified type (e.g. JsonArray or JsonObject)
  • add() adds elements to the root array
  • capacity() returns the capacity of the memory pool
  • clear() empties the document and resets the memory pool
  • containsKey() tests if the root object contains the specified key
  • createNestedArray() creates a nested array attached to the root
  • createNestedObject() create a nested object attached to the root
  • garbageCollect() reclaims leaked memory blocks 🆕
  • operator[] gets or sets values in the document
  • is<T>() tests the type of the root
  • isNull() tells if the document is null or empty
  • memoryUsage() tells how many bytes are used in the memory pool
  • nesting() returns the number of nesting layers in the document
  • remove() removes an element (or member) at the specified index (or key)
  • set() replaces the root with the specified value
  • shrinkToFit() reduces the capacity of the memory pool to match the current usage
  • size() returns the number of elements (or members) that the root array (or object) contains
  • to<T>() clears the document and converts it to the specified type (e.g. JsonArray or JsonObject)


Here is a program that deserializes a JSON document using a DynamicJsonDocument:

DynamicJsonDocument doc(2048);

char json[] = "{\"hello\":\"world\"}";
deserializeJson(doc, json);

const char* world = doc["hello"];


In older versions, DynamicJsonDocument was able to grow if needed. Starting with version 6.7.0, DynamicJsonDocument has a fixed capacity, just like StaticJsonDocument. This change allows better performance, smaller code, and no heap fragmentation.

Arduino 6.6.0 contained a full-blown allocator (i.e., non-monotonic) and was able to compact the memory inside the JsonDocument. This feature was reverted in version 6.7.0 because the overhead was unacceptable.

See also