A basic_json value stores JSON data, but most of the time you want to move that data into ordinary C++ types (an #!cpp int, a #!cpp std::string, a #!cpp std::vector, or one of your own structs) and back. This page describes how these conversions work.
The get function template returns a copy of the stored value converted to the requested type:
json j = R"({"name": "Mary", "age": 42, "hobbies": ["hiking", "reading"]})"_json; auto name = j["name"].get<std::string>(); // "Mary" auto age = j["age"].get<int>(); // 42 auto hobbies = j["hobbies"].get<std::vector<std::string>>(); // {"hiking", "reading"}
!!! note “Getting a string without quotes”
A frequent point of confusion: use [`get`](../api/basic_json/get.md), **not** [`dump`](serialization.md), to read a string value. `#!cpp j["name"].get<std::string>()` yields `#!cpp Mary`, whereas `#!cpp j["name"].dump()` yields the JSON text `#!cpp "Mary"` (**with** quotes), because `dump` always produces a JSON text.
Alternatively, get_to writes into an existing variable and deduces the target type, which avoids repeating it:
??? example
```cpp --8<-- "examples/get_to.cpp" ``` Output: ```json --8<-- "examples/get_to.output" ```
The library already knows how to convert to and from the scalar types and the STL containers (such as #!cpp std::vector, #!cpp std::map, #!cpp std::array, #!cpp std::optional, and many more). Converting a JSON object back to a #!cpp std::map or a JSON array back to a #!cpp std::vector therefore works without any extra code:
json j = {{"one", 1}, {"two", 2}}; auto m = j.get<std::map<std::string, int>>(); // {{"one", 1}, {"two", 2}}
#!cpp std::pair and #!cpp std::tuple are also supported, converting positionally to and from a JSON array:
json j = {1.0, "hello", 42}; auto t = j.get<std::tuple<double, std::string, int>>(); // {1.0, "hello", 42}
!!! info “Extracting references into a tuple”
A tuple type may also hold references (e.g. `#!cpp std::tuple<double&, std::string&>`) to avoid copying: `get`
then returns a tuple of references pointing directly at the elements stored inside the `basic_json` array,
rather than a tuple of copies:
```cpp
json j = {1.0, "hello"};
auto refs = j.get<std::tuple<double&, std::string&>>();
std::get<1>(refs) = "world"; // modifies j[1] in place
```
A referenced type must be one the library actually stores (or an arithmetic type it can convert to/from);
otherwise this is a compile error.
By default, a JSON value implicitly converts to a compatible C++ type, so the explicit get call can often be omitted:
json j = "Hello"; std::string s = j; // implicit conversion, same as j.get<std::string>()
Implicit conversions are convenient but can be surprising (for example, in overload resolution or with auto). They can be disabled by defining JSON_USE_IMPLICIT_CONVERSIONS to #!cpp 0, which forces the explicit get form and can catch unintended conversions at compile time.
!!! warning “Conversions do not range-check numbers”
Just like C++ itself, the `get` family performs numeric conversions without range checks — retrieving a floating-point value as an integer truncates it, and narrowing conversions may overflow. See [number conversion](types/number_handling.md#number-conversion) for details and how to guard against it.
!!! warning “std::optional direct construction from JSON null throws”
Constructing or assigning `std::optional<T>` directly from a JSON value does not correctly produce `std::nullopt` for a JSON `null`: ```cpp json j_null; std::optional<std::string> opt = j_null; // ❌ throws type_error 302 ``` This is due to C++ language rules: `std::optional<T>` has its own converting constructor that is chosen over `basic_json::operator T()` when both are viable. Use `get<std::optional<T>>()` or `get_to()` instead: ```cpp auto opt = j_null.get<std::optional<std::string>>(); // ✅ std::nullopt j_null.get_to(opt); // ✅ std::nullopt ```
!!! warning “static_cast and get<std::optional<T>>() are not guaranteed equivalent”
`operator ValueType()` (used by `static_cast` and implicit conversions) intentionally excludes `std::optional<T>` from delegating to `get<T>()`, to avoid a constructor ambiguity with `std::optional<T>`'s own converting constructor from `basic_json`. As a result, `static_cast<std::optional<T>>(json_value)` goes through `std::optional<T>`'s own converting constructor rather than through `get<std::optional<T>>()`, which can behave differently -- for example, with a custom `adl_serializer<std::optional<T>>` specialization. Prefer `get<std::optional<T>>()`/`get_to()` over `static_cast` for optional types.
!!! warning “Converting to a fixed-size std::array does not check length”
Converting a JSON array to `#!cpp std::array<T, N>` does not check that the JSON array's size matches `N`:
if the JSON array is longer, the extra elements are silently dropped; if it is shorter, the remaining
`std::array` elements are left default-constructed. No exception is thrown in either case.
```cpp
json j = {1, 2, 3, 4, 5};
auto a = j.get<std::array<int, 3>>(); // {1, 2, 3} -- elements 4 and 5 silently dropped
```
std::optionalBy default, to_json for std::optional<T> writes either the value or #!json null -- there is no built-in way to make a field disappear from the serialized object entirely when the std::optional is std::nullopt. Because a specialization of adl_serializer<std::optional<T>> only controls how the value is converted (it cannot prevent the containing object‘s to_json from inserting the key in the first place), omission has to be implemented in the containing type’s to_json:
struct person { std::string name; std::optional<int> age; }; void to_json(json& j, const person& p) { j = json{{"name", p.name}}; if (p.age) { j["age"] = *p.age; // key is only inserted when the optional has a value } }
The reverse direction works the same way: assigning or constructing a json from a C++ value converts it to JSON.
std::vector<int> numbers = {1, 2, 3}; json j = numbers; // [1,2,3]
!!! info “Constructing from a C++20 range view”
A `json` array can also be constructed directly from a C++20 range view (`std::ranges::view`), such as the result
of `std::views::filter` or `std::views::transform` -- no intermediate container is needed:
```cpp
std::vector<int> nums{1, 2, 37, 42, 21};
auto filtered = nums | std::views::filter([](int i) { return i > 10; });
json j(filtered); // [37,42,21]
```
This requires [`JSON_HAS_RANGES`](../api/macros/json_has_ranges.md) to be enabled and is unavailable on MinGW due
to incomplete C++20 ranges support there.
The conversions above are built in for standard types. To make the same syntax work for your own types, provide to_json/from_json functions (or use one of the convenience macros). This is described in detail on the arbitrary types conversions page. Enums can be mapped to strings as described in specializing enum conversion.
get - get a copy converted to a given typeget_to - convert into an existing variableget_ref / get_ptr - access the stored value without copyingJSON_USE_IMPLICIT_CONVERSIONS - toggle implicit conversions