diff --git a/CMakeLists.txt b/CMakeLists.txt
index 82b361298f..7a3ede5f49 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -293,7 +293,9 @@ set(IO_SOURCE
src/IO/AbstractIOHandlerHelper.cpp
src/IO/IOTask.cpp
src/IO/HDF5/HDF5IOHandler.cpp
- src/IO/HDF5/ParallelHDF5IOHandler.cpp)
+ src/IO/HDF5/ParallelHDF5IOHandler.cpp
+ src/IO/JSON/JSONIOHandler.cpp
+ src/IO/JSON/JSONIOHandlerImpl.cpp)
set(IO_ADIOS1_SEQUENTIAL_SOURCE
src/IO/AbstractIOHandler.cpp
src/IO/AbstractIOHandlerImpl.cpp
diff --git a/README.md b/README.md
index 88a1b80e9f..ab2f8c4d0e 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,7 @@ Shipped internally in `share/openPMD/thirdParty/`:
* [NLohmann-JSON](https://github.com/nlohmann/json) 3.4.0+ ([MIT](https://github.com/nlohmann/json/blob/develop/LICENSE.MIT))
Optional I/O backends:
-* [JSON](https://en.wikipedia.org/wiki/JSON) (*not yet implemented*)
+* [JSON](https://en.wikipedia.org/wiki/JSON)
* [HDF5](https://support.hdfgroup.org/HDF5) 1.8.13+
* [ADIOS1](https://www.olcf.ornl.gov/center-projects/adios) 1.13.1+
* [ADIOS2](https://github.com/ornladios/ADIOS2) 2.1+ (*not yet implemented*)
@@ -175,7 +175,7 @@ CMake controls options with prefixed `-D`, e.g. `-DopenPMD_USE_MPI=OFF`:
| CMake Option | Values | Description |
|------------------------------|------------------|------------------------------------------------------------------------------|
| `openPMD_USE_MPI` | **AUTO**/ON/OFF | Enable MPI support |
-| `openPMD_USE_JSON` | **AUTO**/ON/OFF | Enable support for JSON 1 |
+| `openPMD_USE_JSON` | **AUTO**/ON/OFF | Enable support for JSON |
| `openPMD_USE_HDF5` | **AUTO**/ON/OFF | Enable support for HDF5 |
| `openPMD_USE_ADIOS1` | **AUTO**/ON/OFF | Enable support for ADIOS1 |
| `openPMD_USE_ADIOS2` | AUTO/ON/**OFF** | Enable support for ADIOS2 1 |
diff --git a/docs/source/backends/json.rst b/docs/source/backends/json.rst
new file mode 100644
index 0000000000..bccedc5f17
--- /dev/null
+++ b/docs/source/backends/json.rst
@@ -0,0 +1,82 @@
+.. _backends-json:
+
+JSON Backend
+============
+
+openPMD supports writing to and reading from JSON files.
+For this, the installed copy of openPMD must have been built with support for the JSON backend.
+To build openPMD with support for JSON, use the CMake option ``-DopenPMD_USE_JSON=ON``.
+For further information, check out the :ref:`installation guide `,
+:ref:`build dependencies ` and the :ref:`build options `.
+
+
+JSON File Format
+----------------
+A JSON file uses the file ending ``.json``. The JSON backend is chosen by creating
+a ``Series`` object with a filename that has this file ending.
+
+The top-level JSON object is a group representing the openPMD root group ``"/"``.
+Any **openPMD group** is represented in JSON as a JSON object with three keys:
+
+ * ``attributes``: Attributes associated with the group.
+ * ``subgroups``: A JSON array of groups that appear below the current group.
+ * ``datasets``: A JSON array of datasets contained in the group.
+
+Any of these keys may point to ``null`` or not be present,
+thus representing an empty array / object.
+
+Additionally to the three mentioned keys, the top-level group stores information about
+the byte widths specific to the writing platform behind the key ``platform_byte_widths``.
+Will be overwritten every time that a JSON value is stored to disk, hence this information
+is only available about the last platform writing the JSON value.
+
+Any **openPMD dataset** is a JSON object with four keys:
+
+ * ``attributes``: Attributes associated with the dataset. May be ``null`` or not present if no attributes are associated with the dataset.
+ * ``datatype``: A string describing the type of the stored data.
+ * ``extent``: A JSON array describing the extent of the dataset in every dimension.
+ * ``data`` A nested array storing the actual data in row-major manner.
+ The data needs to be consistent with the fields ``datatype`` and ``extent``.
+
+**Attributes** are stored as a JSON object with a key for each attribute.
+Every such attribute is itself a JSON object with two keys:
+
+ * ``datatype``: A string describing the type of the value.
+ * ``value``: The actual value of type ``datatype``.
+
+Restrictions
+------------
+For creation of JSON serializations (i.e. writing), the restrictions of the JSON backend are
+equivalent to those of the `JSON library by Niels Lohmann `_
+used by the openPMD backend.
+
+Numerical values, integral as well as floating point, are supported up to a length of
+64 bits.
+Since JSON does not support special floating point values (i.e. NaN, Infinity, -Infinity),
+those values are rendered as ``null``.
+
+Instructing openPMD to write values of a datatype that is too wide for the JSON
+backend does *not* result in an error:
+ * If casting the value to the widest supported datatype of the same category (integer or floating point)
+ is possible without data loss, the cast is performed and the value is written.
+ As an example, on a platform with ``sizeof(double) == 8``, writing the value
+ ``static_cast(std::numeric_limits::max())`` will work as expected
+ since it can be cast back to ``double``.
+ * Otherwise, a ``null`` value is written.
+
+Upon reading ``null`` when expecting a floating point number, a NaN value will be
+returned. Take notice that a NaN value returned from the deserialization process
+may have originally been +/-Infinity or beyond the supported value range.
+
+Upon reading ``null`` when expecting any other datatype, the JSON backend will
+propagate the exception thrown by Niels Lohmann's library.
+
+A parallel (i.e. MPI) implementation is *not* available.
+
+Example
+-------
+The example code in the :ref:`usage section ` will produce the following JSON serialization
+when picking the JSON backend:
+
+.. literalinclude:: json_example.json
+
diff --git a/docs/source/backends/json_example.json b/docs/source/backends/json_example.json
new file mode 100644
index 0000000000..ca4e9ea88a
--- /dev/null
+++ b/docs/source/backends/json_example.json
@@ -0,0 +1,154 @@
+{
+ "attributes": {
+ "basePath": {
+ "datatype": "STRING",
+ "value": "/data/%T/"
+ },
+ "iterationEncoding": {
+ "datatype": "STRING",
+ "value": "groupBased"
+ },
+ "iterationFormat": {
+ "datatype": "STRING",
+ "value": "/data/%T/"
+ },
+ "meshesPath": {
+ "datatype": "STRING",
+ "value": "meshes/"
+ },
+ "openPMD": {
+ "datatype": "STRING",
+ "value": "1.1.0"
+ },
+ "openPMDextension": {
+ "datatype": "UINT",
+ "value": 0
+ }
+ },
+ "platform_byte_widths": {
+ "BOOL": 1,
+ "CHAR": 1,
+ "DOUBLE": 8,
+ "FLOAT": 4,
+ "INT": 4,
+ "LONG": 8,
+ "LONGLONG": 8,
+ "LONG_DOUBLE": 16,
+ "SHORT": 2,
+ "UCHAR": 1,
+ "UINT": 4,
+ "ULONG": 8,
+ "ULONGLONG": 8,
+ "USHORT": 2
+ },
+ "subgroups": {
+ "data": {
+ "subgroups": {
+ "1": {
+ "attributes": {
+ "dt": {
+ "datatype": "DOUBLE",
+ "value": 1
+ },
+ "time": {
+ "datatype": "DOUBLE",
+ "value": 0
+ },
+ "timeUnitSI": {
+ "datatype": "DOUBLE",
+ "value": 1
+ }
+ },
+ "subgroups": {
+ "meshes": {
+ "datasets": {
+ "rho": {
+ "attributes": {
+ "axisLabels": {
+ "datatype": "VEC_STRING",
+ "value": [
+ "x"
+ ]
+ },
+ "dataOrder": {
+ "datatype": "STRING",
+ "value": "C"
+ },
+ "geometry": {
+ "datatype": "STRING",
+ "value": "cartesian"
+ },
+ "gridGlobalOffset": {
+ "datatype": "VEC_DOUBLE",
+ "value": [
+ 0
+ ]
+ },
+ "gridSpacing": {
+ "datatype": "VEC_DOUBLE",
+ "value": [
+ 1
+ ]
+ },
+ "gridUnitSI": {
+ "datatype": "DOUBLE",
+ "value": 1
+ },
+ "position": {
+ "datatype": "VEC_DOUBLE",
+ "value": [
+ 0
+ ]
+ },
+ "timeOffset": {
+ "datatype": "FLOAT",
+ "value": 0
+ },
+ "unitDimension": {
+ "datatype": "ARR_DBL_7",
+ "value": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ]
+ },
+ "unitSI": {
+ "datatype": "DOUBLE",
+ "value": 1
+ }
+ },
+ "data": [
+ [
+ 0,
+ 1,
+ 2
+ ],
+ [
+ 3,
+ 4,
+ 5
+ ],
+ [
+ 6,
+ 7,
+ 8
+ ]
+ ],
+ "datatype": "DOUBLE",
+ "extent": [
+ 3,
+ 3
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/docs/source/dev/buildoptions.rst b/docs/source/dev/buildoptions.rst
index bcae829343..e016a38ef4 100644
--- a/docs/source/dev/buildoptions.rst
+++ b/docs/source/dev/buildoptions.rst
@@ -15,7 +15,7 @@ CMake controls options with prefixed ``-D``, e.g. ``-DopenPMD_USE_MPI=OFF``:
CMake Option Values Description
============================== =============== ========================================================================
``openPMD_USE_MPI`` **AUTO**/ON/OFF Enable MPI support
-``openPMD_USE_JSON`` **AUTO**/ON/OFF Enable support for JSON :sup:`1`
+``openPMD_USE_JSON`` **AUTO**/ON/OFF Enable support for JSON
``openPMD_USE_HDF5`` **AUTO**/ON/OFF Enable support for HDF5
``openPMD_USE_ADIOS1`` **AUTO**/ON/OFF Enable support for ADIOS1
``openPMD_USE_ADIOS2`` AUTO/ON/**OFF** Enable support for ADIOS2 :sup:`1`
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 1d56bc50de..7b907c34a6 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -83,3 +83,13 @@ Development
dev/sphinx
dev/doxygen
dev/release
+
+********
+Backends
+********
+.. toctree::
+ :caption: BACKENDS
+ :maxdepth: 1
+ :hidden:
+
+ backends/json
diff --git a/docs/source/usage/firststeps.rst b/docs/source/usage/firststeps.rst
index be53d92d60..a799ca56ae 100644
--- a/docs/source/usage/firststeps.rst
+++ b/docs/source/usage/firststeps.rst
@@ -1,4 +1,4 @@
-.. usage-firststeps:
+.. _usage-firststeps:
First Steps
===========
diff --git a/docs/source/usage/parallel.rst b/docs/source/usage/parallel.rst
index 17c2c881bf..c98e362929 100644
--- a/docs/source/usage/parallel.rst
+++ b/docs/source/usage/parallel.rst
@@ -1,4 +1,4 @@
-.. usage-parallel:
+.. _usage-parallel:
Parallel API
============
diff --git a/docs/source/usage/serial.rst b/docs/source/usage/serial.rst
index fc92894d5d..fe77c2d446 100644
--- a/docs/source/usage/serial.rst
+++ b/docs/source/usage/serial.rst
@@ -1,4 +1,4 @@
-.. usage-serial:
+.. _usage-serial:
Serial API
==========
diff --git a/include/openPMD/Datatype.hpp b/include/openPMD/Datatype.hpp
index 887aab2fe5..c0c19a2e0d 100644
--- a/include/openPMD/Datatype.hpp
+++ b/include/openPMD/Datatype.hpp
@@ -28,7 +28,8 @@
#include
#include
#include
-
+#include