diff --git a/.ci/make_and_test.sh b/.ci/make_and_test.sh
index 2ba81aeef..e05ae1409 100755
--- a/.ci/make_and_test.sh
+++ b/.ci/make_and_test.sh
@@ -1,11 +1,14 @@
 #!/usr/bin/env bash
 echo -en "travis_fold:start:script.build\\r"
 echo "Building..."
+STD=$1
+shift
 set -evx
 
+
 mkdir -p build
 cd build
-cmake .. -DCLI11_CXX_STD=$1 -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
+cmake .. -DCLI11_CXX_STD=$STD -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache $@
 cmake --build . -- -j2
 
 set +evx
diff --git a/.gitmodules b/.gitmodules
index 2b5117d2c..e9ec356f3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "extern/sanitizers"]
 	path = extern/sanitizers
 	url = ../../arsenm/sanitizers-cmake
+[submodule "extern/json"]
+	path = extern/json
+	url = ../../nlohmann/json.git
diff --git a/.travis.yml b/.travis.yml
index 1f31e4705..d55169f6c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -76,9 +76,9 @@ matrix:
     - ". .ci/build_lcov.sh"
     - ".ci/run_codecov.sh"
     script:
-    - .ci/make_and_test.sh 11
-    - .ci/make_and_test.sh 14
-    - .ci/make_and_test.sh 17
+    - .ci/make_and_test.sh 11 -DCLI11_EXAMPLE_JSON=ON
+    - .ci/make_and_test.sh 14 -DCLI11_EXAMPLE_JSON=ON
+    - .ci/make_and_test.sh 17 -DCLI11_EXAMPLE_JSON=ON
 
     # GCC 4.7 and Conan
   - compiler: gcc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8bba8c04c..1bb6b139b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@ New for Config file reading and writing [#121]:
 * Has `config_formatter()` and `get_config_formatter()`
 * Dropped prefix argument from `config_to_str`
 * Added `ConfigItem`
+* Added an example of a custom config format using [json](https://github.com/nlohmann/json) [#138]
 
 
 Validators are now much more powerful [#118], all built in validators upgraded to the new form:
@@ -36,9 +37,9 @@ Validators are now much more powerful [#118], all built in validators upgraded t
 
 Other changes:
 
-* Dropped `set_` on Option's `type_name`, `default_str`, and `default_val`
-* Replaced `set_custom_option` with `type_name` and `type_size` instead of `set_custom_option`. Methods return `this`.
-* Removed `set_` from App's `failure_message`, `footer`, `callback`, and `name`
+* Replaced `set_custom_option` with `type_name` and `type_size` instead of `set_custom_option`. Methods return `this`. [#136]
+* Dropped `set_` on Option's `type_name`, `default_str`, and `default_val` [#136]
+* Removed `set_` from App's `failure_message`, `footer`, `callback`, and `name` [#136]
 * Added `->each()` to make adding custom callbacks easier [#126]
 * Added filter argument to `get_subcommands`, `get_options`; use empty filter `{}` to avoid filtering
 * Added `get_groups()` to get groups
@@ -53,6 +54,7 @@ Other changes:
 * Better CMake policy handling [#110]
 * Includes are properly sorted [#120]
 * Help flags now use new `short_circuit` property to simplify parsing [#121]
+* Const added to argv [#126]
 
 [#109]: https://github.com/CLIUtils/CLI11/pull/109
 [#110]: https://github.com/CLIUtils/CLI11/pull/110
@@ -65,6 +67,8 @@ Other changes:
 [#120]: https://github.com/CLIUtils/CLI11/pull/120
 [#121]: https://github.com/CLIUtils/CLI11/pull/121
 [#126]: https://github.com/CLIUtils/CLI11/pull/126
+[#127]: https://github.com/CLIUtils/CLI11/pull/127
+[#138]: https://github.com/CLIUtils/CLI11/pull/138
 
 ### Version 1.5.4: Optionals
 This version fixes the optional search in the single file version; some macros were not yet defined when it did the search. You can define the `CLI11_*_OPTIONAL` macros to 0 if needed to eliminate the search.
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index c4618ca47..2a286a535 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -14,6 +14,30 @@ function(add_cli_exe T)
     endif()
 endfunction()
 
+option(CLI11_EXAMPLE_JSON OFF)
+if(CLI11_EXAMPLE_JSON)
+    if(CMAKE_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
+        message(WARNING "The json example requires GCC 4.9+ (requirement on json library)")
+    endif()
+    add_cli_exe(json json.cpp)
+    target_include_directories(json PUBLIC SYSTEM ../extern/json/single_include)
+
+    add_test(NAME json_config_out COMMAND json --item 2)
+    set_property(TEST json_config_out PROPERTY PASS_REGULAR_EXPRESSION
+        "{"
+        "\"item\": \"2\""
+        "\"simple\": false"
+        "}")
+
+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/input.json" [=[{"item":3,"simple":false}]=])
+    add_test(NAME json_config_in COMMAND json --config "${CMAKE_CURRENT_BINARY_DIR}/input.json")
+    set_property(TEST json_config_in PROPERTY PASS_REGULAR_EXPRESSION
+        "{"
+        "\"item\": \"3\""
+        "\"simple\": false"
+        "}")
+endif()
+
 add_cli_exe(simple simple.cpp)
 add_test(NAME simple_basic COMMAND simple)
 add_test(NAME simple_all COMMAND simple -f filename.txt -c 12 --flag --flag -d 1.2)
diff --git a/examples/json.cpp b/examples/json.cpp
new file mode 100644
index 000000000..bce5ecdab
--- /dev/null
+++ b/examples/json.cpp
@@ -0,0 +1,113 @@
+#include <CLI/CLI.hpp>
+#include <nlohmann/json.hpp>
+
+// This example is only built on GCC 7 on Travis due to mismatch in stdlib
+// for clang (CLI11 is forgiving about mismatches, json.hpp is not)
+
+using nlohmann::json;
+
+class ConfigJSON : public CLI::Config {
+  public:
+    std::string to_config(const CLI::App *app, bool default_also, bool, std::string) const override {
+
+        json j;
+
+        for(const CLI::Option *opt : app->get_options({})) {
+
+            // Only process option with a long-name and configurable
+            if(!opt->get_lnames().empty() && opt->get_configurable()) {
+                std::string name = opt->get_lnames()[0];
+
+                // Non-flags
+                if(opt->get_type_size() != 0) {
+
+                    // If the option was found on command line
+                    if(opt->count() == 1)
+                        j[name] = opt->results().at(0);
+                    else if(opt->count() > 1)
+                        j[name] = opt->results();
+
+                    // If the option has a default and is requested by optional argument
+                    else if(default_also && !opt->get_defaultval().empty())
+                        j[name] = opt->get_defaultval();
+
+                    // Flag, one passed
+                } else if(opt->count() == 1) {
+                    j[name] = true;
+
+                    // Flag, multiple passed
+                } else if(opt->count() > 1) {
+                    j[name] = opt->count();
+
+                    // Flag, not present
+                } else if(opt->count() == 0 && default_also) {
+                    j[name] = false;
+                }
+            }
+        }
+
+        for(const CLI::App *subcom : app->get_subcommands({}))
+            j[subcom->get_name()] = json(to_config(subcom, default_also, false, ""));
+
+        return j.dump(4);
+    }
+
+    std::vector<CLI::ConfigItem> from_config(std::istream &input) const override {
+        json j;
+        input >> j;
+        return _from_config(j);
+    }
+
+    std::vector<CLI::ConfigItem>
+    _from_config(json j, std::string name = "", std::vector<std::string> prefix = {}) const {
+        std::vector<CLI::ConfigItem> results;
+
+        if(j.is_object()) {
+            for(json::iterator item = j.begin(); item != j.end(); ++item) {
+                auto copy_prefix = prefix;
+                if(!name.empty())
+                    copy_prefix.push_back(name);
+                auto sub_results = _from_config(*item, item.key(), copy_prefix);
+                results.insert(results.end(), sub_results.begin(), sub_results.end());
+            }
+        } else if(!name.empty()) {
+            results.emplace_back();
+            CLI::ConfigItem &res = results.back();
+            res.name = name;
+            res.parents = prefix;
+            if(j.is_boolean()) {
+                res.inputs = {j.get<bool>() ? "true" : "false"};
+            } else if(j.is_number()) {
+                std::stringstream ss;
+                ss << j.get<double>();
+                res.inputs = {ss.str()};
+            } else if(j.is_string()) {
+                res.inputs = {j.get<std::string>()};
+            } else if(j.is_array()) {
+                for(std::string ival : j)
+                    res.inputs.push_back(ival);
+            } else {
+                throw CLI::ConversionError("Failed to convert " + name);
+            }
+        } else {
+            throw CLI::ConversionError("You must make all top level values objects in json!");
+        }
+
+        return results;
+    }
+};
+
+int main(int argc, char **argv) {
+    CLI::App app;
+    app.config_formatter(std::make_shared<ConfigJSON>());
+
+    int item;
+
+    app.add_flag("--simple");
+    app.add_option("--item", item);
+    app.set_config("--config");
+
+    CLI11_PARSE(app, argc, argv);
+
+    std::cout << app.config_to_str(true, true) << std::endl;
+}
diff --git a/extern/json b/extern/json
new file mode 160000
index 000000000..d2dd27dc3
--- /dev/null
+++ b/extern/json
@@ -0,0 +1 @@
+Subproject commit d2dd27dc3b8472dbaa7d66f83619b3ebcd9185fe
diff --git a/include/CLI/ConfigFwd.hpp b/include/CLI/ConfigFwd.hpp
index 691a0f164..cdce642c5 100644
--- a/include/CLI/ConfigFwd.hpp
+++ b/include/CLI/ConfigFwd.hpp
@@ -70,27 +70,7 @@ class Config {
     virtual std::vector<ConfigItem> from_config(std::istream &) const = 0;
 
     /// Convert a flag to a bool
-    virtual std::vector<std::string> to_flag(const ConfigItem &) const = 0;
-
-    /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure
-    std::vector<ConfigItem> from_file(const std::string &name) {
-        std::ifstream input{name};
-        if(!input.good())
-            throw FileError::Missing(name);
-
-        return from_config(input);
-    }
-
-    /// virtual destructor
-    virtual ~Config() = default;
-};
-
-/// This converter works with INI files
-class ConfigINI : public Config {
-  public:
-    std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override;
-
-    std::vector<std::string> to_flag(const ConfigItem &item) const override {
+    virtual std::vector<std::string> to_flag(const ConfigItem &item) const {
         if(item.inputs.size() == 1) {
             std::string val = item.inputs.at(0);
             val = detail::to_lower(val);
@@ -112,6 +92,24 @@ class ConfigINI : public Config {
         }
     }
 
+    /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure
+    std::vector<ConfigItem> from_file(const std::string &name) {
+        std::ifstream input{name};
+        if(!input.good())
+            throw FileError::Missing(name);
+
+        return from_config(input);
+    }
+
+    /// virtual destructor
+    virtual ~Config() = default;
+};
+
+/// This converter works with INI files
+class ConfigINI : public Config {
+  public:
+    std::string to_config(const App *, bool default_also, bool write_description, std::string prefix) const override;
+
     std::vector<ConfigItem> from_config(std::istream &input) const override {
         std::string line;
         std::string section = "default";