diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 2e9235f631..16642e1c9f 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -97,13 +97,6 @@ set( KICOMMON_SRCS
     kicad_curl/kicad_curl.cpp
     kicad_curl/kicad_curl_easy.cpp
 
-    settings/aui_settings.cpp
-    settings/bom_settings.cpp
-    settings/grid_settings.cpp
-    settings/json_settings.cpp
-    settings/nested_settings.cpp
-    settings/parameters.cpp
-
     widgets/progress_reporter_base.cpp
     widgets/std_bitmap_button.cpp
 
@@ -142,8 +135,6 @@ add_library( kicommon SHARED
     ${KICOMMON_SRCS}
     )
 
-set_target_properties(kicommon PROPERTIES CXX_VISIBILITY_PRESET hidden)
-
 target_link_libraries( kicommon
     core
     kimath
@@ -573,9 +564,15 @@ set( COMMON_SRCS
     tool/zoom_tool.cpp
 
     settings/app_settings.cpp
+    settings/aui_settings.cpp
+    settings/bom_settings.cpp
     settings/color_settings.cpp
     settings/cvpcb_settings.cpp
     settings/common_settings.cpp
+    settings/grid_settings.cpp
+    settings/json_settings.cpp
+    settings/nested_settings.cpp
+    settings/parameters.cpp
     settings/settings_manager.cpp
     settings/kicad_settings.cpp
 
diff --git a/common/database/database_lib_settings.cpp b/common/database/database_lib_settings.cpp
index 541e45344d..39929e7807 100644
--- a/common/database/database_lib_settings.cpp
+++ b/common/database/database_lib_settings.cpp
@@ -22,7 +22,7 @@
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */
 
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 
 #include <database/database_lib_settings.h>
 #include <settings/parameters.h>
diff --git a/common/io/easyeda/easyeda_parser_structs.cpp b/common/io/easyeda/easyeda_parser_structs.cpp
index e9f4f349d5..567aeb67f5 100644
--- a/common/io/easyeda/easyeda_parser_structs.cpp
+++ b/common/io/easyeda/easyeda_parser_structs.cpp
@@ -24,7 +24,7 @@
 
 #include "easyeda_parser_structs.h"
 
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 
 
diff --git a/common/io/easyedapro/easyedapro_import_utils.cpp b/common/io/easyedapro/easyedapro_import_utils.cpp
index 14f211af63..0d530cb6c6 100644
--- a/common/io/easyedapro/easyedapro_import_utils.cpp
+++ b/common/io/easyedapro/easyedapro_import_utils.cpp
@@ -29,7 +29,7 @@
 
 #include <ki_exception.h>
 #include <string_utils.h>
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 
 #include <wx/log.h>
diff --git a/common/io/easyedapro/easyedapro_parser.cpp b/common/io/easyedapro/easyedapro_parser.cpp
index 1bfeced634..b1f0f18785 100644
--- a/common/io/easyedapro/easyedapro_parser.cpp
+++ b/common/io/easyedapro/easyedapro_parser.cpp
@@ -26,7 +26,7 @@
 
 #include <memory>
 
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 #include <string_utils.h>
 
diff --git a/common/notifications_manager.cpp b/common/notifications_manager.cpp
index 4c3358a633..ea0a39b0f1 100644
--- a/common/notifications_manager.cpp
+++ b/common/notifications_manager.cpp
@@ -36,13 +36,13 @@
 
 #include <notifications_manager.h>
 #include <widgets/kistatusbar.h>
-#include <json_common.h>
 
 #include "core/wx_stl_compat.h"
 
 #include <algorithm>
 #include <fstream>
 #include <map>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 #include <optional>
 #include <string>
diff --git a/common/project/net_settings.cpp b/common/project/net_settings.cpp
index ba265c619c..98453c48a4 100644
--- a/common/project/net_settings.cpp
+++ b/common/project/net_settings.cpp
@@ -23,6 +23,7 @@
 
 #include <project/net_settings.h>
 #include <settings/parameters.h>
+#include <settings/json_settings_internals.h>
 #include <settings/settings_manager.h>
 #include <string_utils.h>
 #include <base_units.h>
diff --git a/common/settings/common_settings.cpp b/common/settings/common_settings.cpp
index 4fb2b856ff..53c0fc438f 100644
--- a/common/settings/common_settings.cpp
+++ b/common/settings/common_settings.cpp
@@ -27,7 +27,7 @@
 #include <search_stack.h>
 #include <settings/settings_manager.h>
 #include <settings/common_settings.h>
-#include <settings/json_settings.h>
+#include <settings/json_settings_internals.h>
 #include <settings/parameters.h>
 #include <systemdirsappend.h>
 #include <trace_helpers.h>
diff --git a/common/settings/json_settings.cpp b/common/settings/json_settings.cpp
index 6f4c8bbcab..3846ab78e5 100644
--- a/common/settings/json_settings.cpp
+++ b/common/settings/json_settings.cpp
@@ -43,6 +43,8 @@
 #include <wx/stdstream.h>
 #include <wx/wfstream.h>
 
+const wxChar* const traceSettings = wxT( "KICAD_SETTINGS" );
+
 
 nlohmann::json::json_pointer JSON_SETTINGS_INTERNALS::PointerFromString( std::string aPath )
 {
@@ -589,37 +591,23 @@ std::optional<ValueType> JSON_SETTINGS::Get( const std::string& aPath ) const
 
 
 // Instantiate all required templates here to allow reducing scope of json.hpp
-template KICOMMON_API std::optional<bool> JSON_SETTINGS::Get<bool>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<double>
-                      JSON_SETTINGS::Get<double>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<float>
-                      JSON_SETTINGS::Get<float>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<int> JSON_SETTINGS::Get<int>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<unsigned int>
-                      JSON_SETTINGS::Get<unsigned int>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<unsigned long long>
-                      JSON_SETTINGS::Get<unsigned long long>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<std::string>
-                      JSON_SETTINGS::Get<std::string>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<nlohmann::json>
-                      JSON_SETTINGS::Get<nlohmann::json>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<KIGFX::COLOR4D>
-                      JSON_SETTINGS::Get<KIGFX::COLOR4D>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<BOM_FIELD>
-                      JSON_SETTINGS::Get<BOM_FIELD>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<BOM_PRESET>
-                      JSON_SETTINGS::Get<BOM_PRESET>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<BOM_FMT_PRESET>
-                      JSON_SETTINGS::Get<BOM_FMT_PRESET>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<GRID> JSON_SETTINGS::Get<GRID>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<wxPoint>
-                      JSON_SETTINGS::Get<wxPoint>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<wxSize>
-                      JSON_SETTINGS::Get<wxSize>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<wxRect>
-                      JSON_SETTINGS::Get<wxRect>( const std::string& aPath ) const;
-template KICOMMON_API std::optional<wxAuiPaneInfo>
-                      JSON_SETTINGS::Get<wxAuiPaneInfo>( const std::string& aPath ) const;
+template std::optional<bool> JSON_SETTINGS::Get<bool>( const std::string& aPath ) const;
+template std::optional<double> JSON_SETTINGS::Get<double>( const std::string& aPath ) const;
+template std::optional<float> JSON_SETTINGS::Get<float>( const std::string& aPath ) const;
+template std::optional<int> JSON_SETTINGS::Get<int>( const std::string& aPath ) const;
+template std::optional<unsigned int> JSON_SETTINGS::Get<unsigned int>( const std::string& aPath ) const;
+template std::optional<unsigned long long> JSON_SETTINGS::Get<unsigned long long>( const std::string& aPath ) const;
+template std::optional<std::string> JSON_SETTINGS::Get<std::string>( const std::string& aPath ) const;
+template std::optional<nlohmann::json> JSON_SETTINGS::Get<nlohmann::json>( const std::string& aPath ) const;
+template std::optional<KIGFX::COLOR4D> JSON_SETTINGS::Get<KIGFX::COLOR4D>( const std::string& aPath ) const;
+template std::optional<BOM_FIELD>  JSON_SETTINGS::Get<BOM_FIELD>( const std::string& aPath ) const;
+template std::optional<BOM_PRESET> JSON_SETTINGS::Get<BOM_PRESET>( const std::string& aPath ) const;
+template std::optional<BOM_FMT_PRESET> JSON_SETTINGS::Get<BOM_FMT_PRESET>( const std::string& aPath ) const;
+template std::optional<GRID>    JSON_SETTINGS::Get<GRID>( const std::string& aPath ) const;
+template std::optional<wxPoint> JSON_SETTINGS::Get<wxPoint>( const std::string& aPath ) const;
+template std::optional<wxSize> JSON_SETTINGS::Get<wxSize>( const std::string& aPath ) const;
+template std::optional<wxRect> JSON_SETTINGS::Get<wxRect>( const std::string& aPath ) const;
+template std::optional<wxAuiPaneInfo> JSON_SETTINGS::Get<wxAuiPaneInfo>( const std::string& aPath ) const;
 
 template<typename ValueType>
 void JSON_SETTINGS::Set( const std::string& aPath, ValueType aVal )
@@ -629,34 +617,24 @@ void JSON_SETTINGS::Set( const std::string& aPath, ValueType aVal )
 
 
 // Instantiate all required templates here to allow reducing scope of json.hpp
-template KICOMMON_API void JSON_SETTINGS::Set<bool>( const std::string& aPath, bool aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<double>( const std::string& aPath, double aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<float>( const std::string& aPath, float aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<int>( const std::string& aPath, int aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<unsigned int>( const std::string& aPath,
-                                                             unsigned int       aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<unsigned long long>( const std::string& aPath,
-                                                                   unsigned long long aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<const char*>( const std::string& aPath,
-                                                            const char*        aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<std::string>( const std::string& aPath,
-                                                            std::string        aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<nlohmann::json>( const std::string& aPath,
-                                                               nlohmann::json     aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<KIGFX::COLOR4D>( const std::string& aPath,
-                                                               KIGFX::COLOR4D     aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<BOM_FIELD>( const std::string& aPath,
-                                                          BOM_FIELD          aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<BOM_PRESET>( const std::string& aPath,
-                                                           BOM_PRESET         aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<BOM_FMT_PRESET>( const std::string& aPath,
-                                                               BOM_FMT_PRESET     aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<GRID>( const std::string& aPath, GRID aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<wxPoint>( const std::string& aPath, wxPoint aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<wxSize>( const std::string& aPath, wxSize aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<wxRect>( const std::string& aPath, wxRect aValue );
-template KICOMMON_API void JSON_SETTINGS::Set<wxAuiPaneInfo>( const std::string& aPath,
-                                                              wxAuiPaneInfo      aValue );
+template void JSON_SETTINGS::Set<bool>( const std::string& aPath, bool aValue );
+template void JSON_SETTINGS::Set<double>( const std::string& aPath, double aValue );
+template void JSON_SETTINGS::Set<float>( const std::string& aPath, float aValue );
+template void JSON_SETTINGS::Set<int>( const std::string& aPath, int aValue );
+template void JSON_SETTINGS::Set<unsigned int>( const std::string& aPath, unsigned int aValue );
+template void JSON_SETTINGS::Set<unsigned long long>( const std::string& aPath, unsigned long long aValue );
+template void JSON_SETTINGS::Set<const char*>( const std::string& aPath, const char* aValue );
+template void JSON_SETTINGS::Set<std::string>( const std::string& aPath, std::string aValue );
+template void JSON_SETTINGS::Set<nlohmann::json>( const std::string& aPath, nlohmann::json aValue );
+template void JSON_SETTINGS::Set<KIGFX::COLOR4D>( const std::string& aPath, KIGFX::COLOR4D aValue );
+template void JSON_SETTINGS::Set<BOM_FIELD>( const std::string& aPath, BOM_FIELD aValue );
+template void JSON_SETTINGS::Set<BOM_PRESET>( const std::string& aPath, BOM_PRESET aValue );
+template void JSON_SETTINGS::Set<BOM_FMT_PRESET>( const std::string& aPath, BOM_FMT_PRESET aValue );
+template void JSON_SETTINGS::Set<GRID>( const std::string& aPath, GRID aValue );
+template void JSON_SETTINGS::Set<wxPoint>( const std::string& aPath, wxPoint aValue );
+template void JSON_SETTINGS::Set<wxSize>( const std::string& aPath, wxSize aValue );
+template void JSON_SETTINGS::Set<wxRect>( const std::string& aPath, wxRect aValue );
+template void JSON_SETTINGS::Set<wxAuiPaneInfo>( const std::string& aPath, wxAuiPaneInfo aValue );
 
 
 void JSON_SETTINGS::registerMigration( int aOldSchemaVersion, int aNewSchemaVersion,
@@ -797,13 +775,13 @@ bool JSON_SETTINGS::fromLegacy( wxConfigBase* aConfig, const std::string& aKey,
 
 // Explicitly declare these because we only support a few types anyway, and it means we can keep
 // wxConfig detail out of the header file
-template KICOMMON_API bool JSON_SETTINGS::fromLegacy<int>( wxConfigBase*, const std::string&,
+template bool JSON_SETTINGS::fromLegacy<int>( wxConfigBase*, const std::string&,
                                               const std::string& );
 
-template KICOMMON_API bool JSON_SETTINGS::fromLegacy<double>( wxConfigBase*, const std::string&,
+template bool JSON_SETTINGS::fromLegacy<double>( wxConfigBase*, const std::string&,
                                                  const std::string& );
 
-template KICOMMON_API bool JSON_SETTINGS::fromLegacy<bool>( wxConfigBase*, const std::string&,
+template bool JSON_SETTINGS::fromLegacy<bool>( wxConfigBase*, const std::string&,
                                                const std::string& );
 
 
@@ -936,10 +914,9 @@ ResultType JSON_SETTINGS::fetchOrDefault( const nlohmann::json& aJson, const std
 }
 
 
-template KICOMMON_API std::string JSON_SETTINGS::fetchOrDefault( const nlohmann::json& aJson,
+template std::string JSON_SETTINGS::fetchOrDefault( const nlohmann::json& aJson,
                                                     const std::string& aKey, std::string aDefault );
 
 
-template KICOMMON_API bool JSON_SETTINGS::fetchOrDefault( const nlohmann::json& aJson,
-                                                         const std::string& aKey,
+template bool JSON_SETTINGS::fetchOrDefault( const nlohmann::json& aJson, const std::string& aKey,
                                              bool aDefault );
diff --git a/common/settings/parameters.cpp b/common/settings/parameters.cpp
index 2b140ac269..87ab25dd5f 100644
--- a/common/settings/parameters.cpp
+++ b/common/settings/parameters.cpp
@@ -22,9 +22,190 @@
 
 #include <nlohmann/json.hpp>
 
+#include <gal/color4d.h>
 #include <project/project_file.h>
 #include <settings/parameters.h>
+#include <settings/bom_settings.h>
+#include <settings/grid_settings.h>
 
+template <typename ValueType>
+void PARAM_LAMBDA<ValueType>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
+{
+    if( m_readOnly )
+        return;
+
+    if( std::is_same<ValueType, nlohmann::json>::value )
+    {
+        if( std::optional<nlohmann::json> optval = aSettings->GetJson( m_path ) )
+            m_setter( *optval );
+        else
+            m_setter( m_default );
+    }
+    else
+    {
+        if( std::optional<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
+            m_setter( *optval );
+        else
+            m_setter( m_default );
+    }
+}
+
+
+template <typename ValueType>
+bool PARAM_LAMBDA<ValueType>::MatchesFile( JSON_SETTINGS* aSettings ) const
+{
+    if( std::is_same<ValueType, nlohmann::json>::value )
+    {
+        if( std::optional<nlohmann::json> optval = aSettings->GetJson( m_path ) )
+            return *optval == m_getter();
+    }
+    else
+    {
+        if( std::optional<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
+            return *optval == m_getter();
+    }
+
+    // Not in file
+    return false;
+}
+
+
+// Instantiate all required templates here to allow reducing scope of json.hpp
+template class PARAM_LAMBDA<bool>;
+template class PARAM_LAMBDA<int>;
+template class PARAM_LAMBDA<nlohmann::json>;
+template class PARAM_LAMBDA<std::string>;
+
+template <typename ValueType>
+void PARAM_LIST<ValueType>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
+{
+    if( m_readOnly )
+        return;
+
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        std::vector<ValueType> val;
+
+        if( js->is_array() )
+        {
+            for( const auto& el : js->items() )
+                val.push_back( el.value().get<ValueType>() );
+        }
+
+        *m_ptr = val;
+    }
+    else if( aResetIfMissing )
+        *m_ptr = m_default;
+}
+
+
+template <typename ValueType>
+void PARAM_LIST<ValueType>::Store( JSON_SETTINGS* aSettings ) const
+{
+    nlohmann::json js = nlohmann::json::array();
+
+    for( const auto& el : *m_ptr )
+        js.push_back( el );
+
+    aSettings->Set<nlohmann::json>( m_path, js );
+}
+
+
+template <typename ValueType>
+bool PARAM_LIST<ValueType>::MatchesFile( JSON_SETTINGS* aSettings ) const
+{
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        if( js->is_array() )
+        {
+            std::vector<ValueType> val;
+
+            for( const auto& el : js->items() )
+            {
+                try
+                {
+                    val.emplace_back( el.value().get<ValueType>() );
+                }
+                catch( ... )
+                {
+                    // Probably typecast didn't work; skip this element
+                }
+            }
+
+            return val == *m_ptr;
+        }
+    }
+
+    return false;
+}
+
+
+template class PARAM_LIST<int>;
+template class PARAM_LIST<double>;
+template class PARAM_LIST<wxString>;
+template class PARAM_LIST<KIGFX::COLOR4D>;
+template class PARAM_LIST<FILE_INFO_PAIR>;
+template class PARAM_LIST<BOM_PRESET>;
+template class PARAM_LIST<BOM_FMT_PRESET>;
+template class PARAM_LIST<GRID>;
+
+
+template <typename ValueType>
+void PARAM_SET<ValueType>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
+{
+    if( m_readOnly )
+        return;
+
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        std::set<ValueType> val;
+
+        if( js->is_array() )
+        {
+            for( const auto& el : js->items() )
+                val.insert( el.value().get<ValueType>() );
+        }
+
+        *m_ptr = val;
+    }
+    else if( aResetIfMissing )
+        *m_ptr = m_default;
+}
+
+
+template <typename ValueType>
+void PARAM_SET<ValueType>::Store( JSON_SETTINGS* aSettings ) const
+{
+    nlohmann::json js = nlohmann::json::array();
+
+    for( const auto& el : *m_ptr )
+        js.push_back( el );
+
+    aSettings->Set<nlohmann::json>( m_path, js );
+}
+
+
+template <typename ValueType>
+bool PARAM_SET<ValueType>::MatchesFile( JSON_SETTINGS* aSettings ) const
+{
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        if( js->is_array() )
+        {
+            std::set<ValueType> val;
+
+            for( const auto& el : js->items() )
+                val.insert( el.value().get<ValueType>() );
+
+            return val == *m_ptr;
+        }
+    }
+
+    return false;
+}
+
+
+template class PARAM_SET<wxString>;
 
 
 void PARAM_PATH_LIST::Store( JSON_SETTINGS* aSettings ) const
@@ -57,6 +238,66 @@ bool PARAM_PATH_LIST::MatchesFile( JSON_SETTINGS* aSettings ) const
 }
 
 
+template <typename Value>
+void PARAM_MAP<Value>::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
+{
+    if( m_readOnly )
+        return;
+
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        if( js->is_object() )
+        {
+            m_ptr->clear();
+
+            for( const auto& el : js->items() )
+                ( *m_ptr )[el.key()] = el.value().get<Value>();
+        }
+    }
+    else if( aResetIfMissing )
+        *m_ptr = m_default;
+}
+
+
+template <typename Value>
+void PARAM_MAP<Value>::Store( JSON_SETTINGS* aSettings ) const
+{
+    nlohmann::json js( {} );
+
+    for( const auto& el : *m_ptr )
+        js[el.first] = el.second;
+
+    aSettings->Set<nlohmann::json>( m_path, js );
+}
+
+
+template <typename Value>
+bool PARAM_MAP<Value>::MatchesFile( JSON_SETTINGS* aSettings ) const
+{
+    if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
+    {
+        if( js->is_object() )
+        {
+            if( m_ptr->size() != js->size() )
+                return false;
+
+            std::map<std::string, Value> val;
+
+            for( const auto& el : js->items() )
+                val[el.key()] = el.value().get<Value>();
+
+            return val == *m_ptr;
+        }
+    }
+
+    return false;
+}
+
+
+template class PARAM_MAP<int>;
+template class PARAM_MAP<double>;
+template class PARAM_MAP<bool>;
+
 
 void PARAM_WXSTRING_MAP::Load( JSON_SETTINGS* aSettings, bool aResetIfMissing ) const
 {
@@ -117,25 +358,3 @@ bool PARAM_WXSTRING_MAP::MatchesFile( JSON_SETTINGS* aSettings ) const
 
     return false;
 }
-
-
-// Instantiate all required templates here and export
-template class KICOMMON_API PARAM_LAMBDA<bool>;
-template class KICOMMON_API PARAM_LAMBDA<int>;
-template class KICOMMON_API PARAM_LAMBDA<nlohmann::json>;
-template class KICOMMON_API PARAM_LAMBDA<std::string>;
-
-template class KICOMMON_API PARAM_LIST<int>;
-template class KICOMMON_API PARAM_LIST<double>;
-template class KICOMMON_API PARAM_LIST<wxString>;
-template class KICOMMON_API PARAM_LIST<KIGFX::COLOR4D>;
-//template KICOMMON_API class PARAM_LIST<FILE_INFO_PAIR>;
-template class KICOMMON_API PARAM_LIST<struct BOM_PRESET>;
-template class KICOMMON_API PARAM_LIST<struct BOM_FMT_PRESET>;
-template class KICOMMON_API PARAM_LIST<GRID>;
-
-template class KICOMMON_API PARAM_SET<wxString>;
-
-template class KICOMMON_API PARAM_MAP<int>;
-template class KICOMMON_API PARAM_MAP<double>;
-template class KICOMMON_API PARAM_MAP<bool>;
\ No newline at end of file
diff --git a/include/import_export.h b/include/import_export.h
index d415814a45..fd302037c9 100644
--- a/include/import_export.h
+++ b/include/import_export.h
@@ -44,16 +44,6 @@
 	#define APILOCAL
 #endif
 
-// We use APIVISIBLE to mark extern template declarations where we cannot use APIEXPORT
-// Because MSVC disallows mixing dllexport and extern templates, we can't just use APIEXPORT
-// However MSVC is fine with the dllexport in the cpp file and extern in the header
-// But we need the visibility declared on both instantiation and extern for GCC/Clang to make
-// the symbol visible
-#if defined( __GNUC__ ) || defined( __clang__ )
-	#define APIVISIBLE __attribute__ ((visibility("default")))
-#else
-	#define APIVISIBLE
-#endif
 
 #if defined(COMPILING_DLL)
 	#define KIFACE_API    APIEXPORT
diff --git a/include/json_common.h b/include/json_common.h
deleted file mode 100644
index 71598dbcc2..0000000000
--- a/include/json_common.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
- *
- * This program is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef JSON_COMMON_H
-#define JSON_COMMON_H
-
-#include <nlohmann/json.hpp>
-
-#include <kicommon.h>
-
-/**
- * This is simply a "stub" meant to inform MSVC when compiling shared libraries that it can find
- * template instances in kicommon of nlohmann::json's various templates
- */
-class KICOMMON_API JSON_COMMON_EXPORT_STUB final : public nlohmann::json
-{
-};
-
-#endif
\ No newline at end of file
diff --git a/include/project/net_settings.h b/include/project/net_settings.h
index ec2ec822c6..2ad4040f9b 100644
--- a/include/project/net_settings.h
+++ b/include/project/net_settings.h
@@ -64,7 +64,7 @@ public:
 
     /**
      * Get a NETCLASS object from a given Netclass name string
-     *
+     * 
      * @param aNetClassName the Netclass name to resolve
      * @return shared pointer to the requested NETCLASS object, or the default NETCLASS
     */
diff --git a/include/settings/aui_settings.h b/include/settings/aui_settings.h
index 1f1b191a67..f4bb8cc056 100644
--- a/include/settings/aui_settings.h
+++ b/include/settings/aui_settings.h
@@ -30,21 +30,21 @@ class wxPoint;
 class wxRect;
 class wxSize;
 
-KICOMMON_API void to_json( nlohmann::json& aJson, const wxPoint& aPoint );
-KICOMMON_API void from_json( const nlohmann::json& aJson, wxPoint& aPoint );
-KICOMMON_API bool operator<( const wxPoint& aLhs, const wxPoint& aRhs );
+extern void to_json( nlohmann::json& aJson, const wxPoint& aPoint );
+extern void from_json( const nlohmann::json& aJson, wxPoint& aPoint );
+extern bool operator<( const wxPoint& aLhs, const wxPoint& aRhs );
 
-KICOMMON_API void to_json( nlohmann::json& aJson, const wxSize& aPoint );
-KICOMMON_API void from_json( const nlohmann::json& aJson, wxSize& aPoint );
-KICOMMON_API bool operator<( const wxSize& aLhs, const wxSize& aRhs );
+extern void to_json( nlohmann::json& aJson, const wxSize& aPoint );
+extern void from_json( const nlohmann::json& aJson, wxSize& aPoint );
+extern bool operator<( const wxSize& aLhs, const wxSize& aRhs );
 
-KICOMMON_API void to_json( nlohmann::json& aJson, const wxRect& aRect );
-KICOMMON_API void from_json( const nlohmann::json& aJson, wxRect& aRect );
-KICOMMON_API bool operator<( const wxRect& aLhs, const wxRect& aRhs );
+extern void to_json( nlohmann::json& aJson, const wxRect& aRect );
+extern void from_json( const nlohmann::json& aJson, wxRect& aRect );
+extern bool operator<( const wxRect& aLhs, const wxRect& aRhs );
 
-KICOMMON_API void to_json( nlohmann::json& aJson, const wxAuiPaneInfo& aPaneInfo );
-KICOMMON_API void from_json( const nlohmann::json& aJson, wxAuiPaneInfo& aPaneInfo );
-KICOMMON_API bool operator<( const wxAuiPaneInfo& aLhs, const wxAuiPaneInfo& aRhs );
-KICOMMON_API bool operator==( const wxAuiPaneInfo& aLhs, const wxAuiPaneInfo& aRhs );
+extern void to_json( nlohmann::json& aJson, const wxAuiPaneInfo& aPaneInfo );
+extern void from_json( const nlohmann::json& aJson, wxAuiPaneInfo& aPaneInfo );
+extern bool operator<( const wxAuiPaneInfo& aLhs, const wxAuiPaneInfo& aRhs );
+extern bool operator==( const wxAuiPaneInfo& aLhs, const wxAuiPaneInfo& aRhs );
 
 #endif // _AUI_SETTINGS_H_
diff --git a/include/settings/bom_settings.h b/include/settings/bom_settings.h
index 57c9313d44..85ea4a245b 100644
--- a/include/settings/bom_settings.h
+++ b/include/settings/bom_settings.h
@@ -27,7 +27,7 @@
 #include <i18n_utility.h>
 
 // A single field within a BOM, e.g. Reference, Value, Footprint
-struct KICOMMON_API BOM_FIELD
+struct BOM_FIELD
 {
     wxString name;
     wxString label;
@@ -37,16 +37,16 @@ struct KICOMMON_API BOM_FIELD
     bool operator==( const BOM_FIELD& rhs ) const;
 };
 
-KICOMMON_API bool operator!=( const BOM_FIELD& lhs, const BOM_FIELD& rhs );
-KICOMMON_API bool  operator<( const BOM_FIELD& lhs, const BOM_FIELD& rhs );
+bool operator!=( const BOM_FIELD& lhs, const BOM_FIELD& rhs );
+bool operator<( const BOM_FIELD& lhs, const BOM_FIELD& rhs );
 
-KICOMMON_API void to_json( nlohmann::json& j, const BOM_FIELD& f );
-KICOMMON_API void  from_json( const nlohmann::json& j, BOM_FIELD& f );
+void to_json( nlohmann::json& j, const BOM_FIELD& f );
+void from_json( const nlohmann::json& j, BOM_FIELD& f );
 
 
 // A complete preset defining a BOM "View" with a list of all the fields to show,
 // group by, order, filtering settings, etc.
-struct KICOMMON_API BOM_PRESET
+struct BOM_PRESET
 {
     wxString               name;
     bool                   readOnly = false;
@@ -66,15 +66,15 @@ struct KICOMMON_API BOM_PRESET
     static std::vector<BOM_PRESET> BuiltInPresets();
 };
 
-KICOMMON_API bool operator!=( const BOM_PRESET& lhs, const BOM_PRESET& rhs );
-KICOMMON_API bool  operator<( const BOM_PRESET& lhs, const BOM_PRESET& rhs );
+bool operator!=( const BOM_PRESET& lhs, const BOM_PRESET& rhs );
+bool operator<( const BOM_PRESET& lhs, const BOM_PRESET& rhs );
 
-KICOMMON_API void to_json( nlohmann::json& j, const BOM_PRESET& f );
-KICOMMON_API void  from_json( const nlohmann::json& j, BOM_PRESET& f );
+void to_json( nlohmann::json& j, const BOM_PRESET& f );
+void from_json( const nlohmann::json& j, BOM_PRESET& f );
 
 
 // A formatting preset, like CSV (Comma Separated Values)
-struct KICOMMON_API BOM_FMT_PRESET
+struct BOM_FMT_PRESET
 {
     wxString name;
     bool     readOnly = false;
@@ -94,11 +94,11 @@ struct KICOMMON_API BOM_FMT_PRESET
     static std::vector<BOM_FMT_PRESET> BuiltInPresets();
 };
 
-KICOMMON_API bool operator!=( const BOM_FMT_PRESET& lhs, const BOM_FMT_PRESET& rhs );
-KICOMMON_API bool  operator<( const BOM_FMT_PRESET& lhs, const BOM_FMT_PRESET& rhs );
+bool operator!=( const BOM_FMT_PRESET& lhs, const BOM_FMT_PRESET& rhs );
+bool operator<( const BOM_FMT_PRESET& lhs, const BOM_FMT_PRESET& rhs );
 
-KICOMMON_API void to_json( nlohmann::json& j, const BOM_FMT_PRESET& f );
-KICOMMON_API void  from_json( const nlohmann::json& j, BOM_FMT_PRESET& f );
+void to_json( nlohmann::json& j, const BOM_FMT_PRESET& f );
+void from_json( const nlohmann::json& j, BOM_FMT_PRESET& f );
 
 
 #endif
diff --git a/include/settings/grid_settings.h b/include/settings/grid_settings.h
index 558e6f0784..50f43fc8d2 100644
--- a/include/settings/grid_settings.h
+++ b/include/settings/grid_settings.h
@@ -30,7 +30,7 @@ class UNITS_PROVIDER;
 /**
  * Common grid settings, available to every frame
  */
-struct KICOMMON_API GRID
+struct GRID
 {
     bool operator==( const GRID& aOther ) const;
 
@@ -53,11 +53,11 @@ struct KICOMMON_API GRID
     wxString y;
 };
 
-KICOMMON_API bool operator!=( const GRID& lhs, const GRID& rhs );
-KICOMMON_API bool  operator<( const GRID& lhs, const GRID& rhs );
+bool operator!=( const GRID& lhs, const GRID& rhs );
+bool operator<( const GRID& lhs, const GRID& rhs );
 
-KICOMMON_API void to_json( nlohmann::json& j, const GRID& g );
-KICOMMON_API void  from_json( const nlohmann::json& j, GRID& g );
+void to_json( nlohmann::json& j, const GRID& g );
+void from_json( const nlohmann::json& j, GRID& g );
 
 
 struct GRID_SETTINGS
diff --git a/include/settings/json_settings.h b/include/settings/json_settings.h
index 2bf0075681..2434a52daa 100644
--- a/include/settings/json_settings.h
+++ b/include/settings/json_settings.h
@@ -28,27 +28,21 @@
 
 #include <functional>
 #include <optional>
-#include <settings/json_settings_internals.h>
-
-#include <kicommon.h>
+#include <nlohmann/json_fwd.hpp>
 
 class wxConfigBase;
 class NESTED_SETTINGS;
 class PARAM_BASE;
 class SETTINGS_MANAGER;
 
-class wxAuiPaneInfo;
-struct BOM_FIELD;
-struct BOM_PRESET;
-struct BOM_FMT_PRESET;
-struct GRID;
-
-namespace KIGFX
-{
-class COLOR4D;
-};
-
-#define traceSettings wxT( "KICAD_SETTINGS" )
+/**
+ * Flag to enable debug output of settings operations and management.
+ *
+ * Use "KICAD_SETTINGS" to enable.
+ *
+ * @ingroup trace_env_vars
+ */
+extern const wxChar* const traceSettings;
 
 enum class SETTINGS_LOC {
     USER,       ///< The main config directory (e.g. ~/.config/kicad/)
@@ -62,7 +56,7 @@ enum class SETTINGS_LOC {
 /// pimpl to allow hiding json.hpp
 class JSON_SETTINGS_INTERNALS;
 
-class KICOMMON_API JSON_SETTINGS
+class JSON_SETTINGS
 {
 public:
     friend class NESTED_SETTINGS;
@@ -346,32 +340,14 @@ protected:
 
 // Specializations to allow conversion between wxString and std::string via JSON_SETTINGS API
 
-template<> KICOMMON_API std::optional<wxString> JSON_SETTINGS::Get( const std::string& aPath ) const;
+template<> std::optional<wxString> JSON_SETTINGS::Get( const std::string& aPath ) const;
 
-template<> KICOMMON_API void JSON_SETTINGS::Set<wxString>( const std::string& aPath, wxString aVal );
+template<> void JSON_SETTINGS::Set<wxString>( const std::string& aPath, wxString aVal );
 
 // Specializations to allow directly reading/writing wxStrings from JSON
 
-KICOMMON_API void to_json( nlohmann::json& aJson, const wxString& aString );
+void to_json( nlohmann::json& aJson, const wxString& aString );
 
-KICOMMON_API void from_json( const nlohmann::json& aJson, wxString& aString );
-
-extern template std::optional<bool>   JSON_SETTINGS::Get<bool>( const std::string& aPath ) const;
-extern template std::optional<double> JSON_SETTINGS::Get<double>( const std::string& aPath ) const;
-extern template std::optional<float>  JSON_SETTINGS::Get<float>( const std::string& aPath ) const;
-extern template std::optional<int>    JSON_SETTINGS::Get<int>( const std::string& aPath ) const;
-extern template std::optional<unsigned int> JSON_SETTINGS::Get<unsigned int>( const std::string& aPath ) const;
-extern template std::optional<unsigned long long> JSON_SETTINGS::Get<unsigned long long>( const std::string& aPath ) const;
-extern template std::optional<std::string> JSON_SETTINGS::Get<std::string>( const std::string& aPath ) const;
-extern template std::optional<nlohmann::json> JSON_SETTINGS::Get<nlohmann::json>( const std::string& aPath ) const;
-extern template std::optional<KIGFX::COLOR4D> JSON_SETTINGS::Get<KIGFX::COLOR4D>( const std::string& aPath ) const;
-extern template std::optional<BOM_FIELD> JSON_SETTINGS::Get<BOM_FIELD>( const std::string& aPath ) const;
-extern template std::optional<BOM_PRESET> JSON_SETTINGS::Get<BOM_PRESET>( const std::string& aPath ) const;
-extern template std::optional<BOM_FMT_PRESET> JSON_SETTINGS::Get<BOM_FMT_PRESET>( const std::string& aPath ) const;
-extern template std::optional<GRID> JSON_SETTINGS::Get<GRID>( const std::string& aPath ) const;
-extern template std::optional<wxPoint> JSON_SETTINGS::Get<wxPoint>( const std::string& aPath ) const;
-extern template std::optional<wxSize> JSON_SETTINGS::Get<wxSize>( const std::string& aPath ) const;
-extern template std::optional<wxRect> JSON_SETTINGS::Get<wxRect>( const std::string& aPath ) const;
-extern template std::optional<wxAuiPaneInfo> JSON_SETTINGS::Get<wxAuiPaneInfo>( const std::string& aPath ) const;
+void from_json( const nlohmann::json& aJson, wxString& aString );
 
 #endif
diff --git a/include/settings/json_settings_internals.h b/include/settings/json_settings_internals.h
index 486a77f119..0f7d4da4b0 100644
--- a/include/settings/json_settings_internals.h
+++ b/include/settings/json_settings_internals.h
@@ -21,9 +21,10 @@
 #ifndef KICAD_JSON_SETTINGS_INTERNALS_H
 #define KICAD_JSON_SETTINGS_INTERNALS_H
 
-#include <json_common.h>
+// This is a pretty heavy file.  Try to use json_fwd.hpp most places.
+#include <nlohmann/json.hpp>
 
-class KICOMMON_API JSON_SETTINGS_INTERNALS : public nlohmann::json
+class JSON_SETTINGS_INTERNALS : public nlohmann::json
 {
     friend class JSON_SETTINGS;
 
diff --git a/include/settings/nested_settings.h b/include/settings/nested_settings.h
index 6ad048cd17..61e2734107 100644
--- a/include/settings/nested_settings.h
+++ b/include/settings/nested_settings.h
@@ -28,7 +28,7 @@
  * NESTED_SETTINGS is a JSON_SETTINGS that lives inside a JSON_SETTINGS.
  * Instead of being backed by a JSON file on disk, it loads and stores to its parent.
  */
-class KICOMMON_API NESTED_SETTINGS : public JSON_SETTINGS
+class NESTED_SETTINGS : public JSON_SETTINGS
 {
 public:
     NESTED_SETTINGS( const std::string& aName, int aSchemaVersion, JSON_SETTINGS* aParent,
diff --git a/include/settings/parameters.h b/include/settings/parameters.h
index 89809bf6bb..0e1583fd51 100644
--- a/include/settings/parameters.h
+++ b/include/settings/parameters.h
@@ -27,13 +27,10 @@
 #include <math/util.h>
 
 #include <optional>
-#include <gal/color4d.h>
 #include <settings/json_settings.h>
-#include <settings/bom_settings.h>
-#include <settings/grid_settings.h>
-#include <kicommon.h>
 
-class KICOMMON_API PARAM_BASE
+
+class PARAM_BASE
 {
 public:
     PARAM_BASE( std::string aJsonPath, bool aReadOnly ) :
@@ -170,7 +167,7 @@ protected:
 /**
  * Stores a path as a string with directory separators normalized to unix-style
  */
-class KICOMMON_API PARAM_PATH : public PARAM<wxString>
+class PARAM_PATH : public PARAM<wxString>
 {
 public:
     PARAM_PATH( const std::string& aJsonPath, wxString* aPtr, const wxString& aDefault,
@@ -302,26 +299,7 @@ public:
             m_setter( std::move( aSetter ) )
     { }
 
-    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
-    {
-        if( m_readOnly )
-            return;
-
-        if( std::is_same<ValueType, nlohmann::json>::value )
-        {
-            if( std::optional<nlohmann::json> optval = aSettings->GetJson( m_path ) )
-                m_setter( *optval );
-            else
-                m_setter( m_default );
-        }
-        else
-        {
-            if( std::optional<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
-                m_setter( *optval );
-            else
-                m_setter( m_default );
-        }
-    }
+    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
 
     void Store( JSON_SETTINGS* aSettings ) const override
     {
@@ -344,22 +322,7 @@ public:
         m_setter( m_default );
     }
 
-    bool MatchesFile( JSON_SETTINGS* aSettings ) const override
-    {
-        if( std::is_same<ValueType, nlohmann::json>::value )
-        {
-            if( std::optional<nlohmann::json> optval = aSettings->GetJson( m_path ) )
-                return *optval == m_getter();
-        }
-        else
-        {
-            if( std::optional<ValueType> optval = aSettings->Get<ValueType>( m_path ) )
-                return *optval == m_getter();
-        }
-
-        // Not in file
-        return false;
-    }
+    bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
 
 private:
     ValueType                        m_default;
@@ -368,11 +331,6 @@ private:
 };
 
 
-extern template class APIVISIBLE PARAM_LAMBDA<bool>;
-extern template class APIVISIBLE PARAM_LAMBDA<int>;
-extern template class APIVISIBLE PARAM_LAMBDA<nlohmann::json>;
-extern template class APIVISIBLE PARAM_LAMBDA<std::string>;
-
 /**
  * Represents a parameter that has a scaling factor between the value in the file and the
  * value used internally (i.e. the value pointer).  This basically only makes sense to use
@@ -481,85 +439,22 @@ public:
             m_default( std::move( aDefault ) )
     { }
 
-    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
-    {
-        if( m_readOnly )
-            return;
+    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
 
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            std::vector<Type> val;
-
-            if( js->is_array() )
-            {
-                for( const auto& el : js->items() )
-                    val.push_back( el.value().get<Type>() );
-            }
-
-            *m_ptr = val;
-        }
-        else if( aResetIfMissing )
-            *m_ptr = m_default;
-    }
-
-    void Store( JSON_SETTINGS* aSettings ) const override
-    {
-        nlohmann::json js = nlohmann::json::array();
-
-        for( const auto& el : *m_ptr )
-            js.push_back( el );
-
-        aSettings->Set<nlohmann::json>( m_path, js );
-    }
+    void Store( JSON_SETTINGS* aSettings) const override;
 
     void SetDefault() override
     {
         *m_ptr = m_default;
     }
 
-    bool MatchesFile( JSON_SETTINGS* aSettings ) const override
-    {
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            if( js->is_array() )
-            {
-                std::vector<Type> val;
-
-                for( const auto& el : js->items() )
-                {
-                    try
-                    {
-                        val.emplace_back( el.value().get<Type>() );
-                    }
-                    catch( ... )
-                    {
-                        // Probably typecast didn't work; skip this element
-                    }
-                }
-
-                return val == *m_ptr;
-            }
-        }
-
-        return false;
-    }
+    bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
 
 protected:
     std::vector<Type>* m_ptr;
     std::vector<Type>  m_default;
 };
 
-
-extern template class APIVISIBLE PARAM_LIST<int>;
-extern template class APIVISIBLE PARAM_LIST<double>;
-extern template class APIVISIBLE PARAM_LIST<KIGFX::COLOR4D>;
-//template KICOMMON_EXTERN_DECL class PARAM_LIST<FILE_INFO_PAIR>;
-extern template class APIVISIBLE PARAM_LIST<struct BOM_PRESET>;
-extern template class APIVISIBLE PARAM_LIST<struct BOM_FMT_PRESET>;
-extern template class APIVISIBLE PARAM_LIST<GRID>;
-extern template class APIVISIBLE PARAM_LIST<wxString>;
-
-
 template<typename Type>
 class PARAM_SET : public PARAM_BASE
 {
@@ -578,73 +473,27 @@ public:
             m_default( aDefault )
     { }
 
-    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
-    {
-        if( m_readOnly )
-            return;
-
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            std::set<Type> val;
-
-            if( js->is_array() )
-            {
-                for( const auto& el : js->items() )
-                    val.insert( el.value().get<Type>() );
-            }
-
-            *m_ptr = val;
-        }
-        else if( aResetIfMissing )
-            *m_ptr = m_default;
-    }
-
-    void Store( JSON_SETTINGS* aSettings) const override
-    {
-        nlohmann::json js = nlohmann::json::array();
-
-        for( const auto& el : *m_ptr )
-            js.push_back( el );
-
-        aSettings->Set<nlohmann::json>( m_path, js );
-    }
+    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
 
+    void Store( JSON_SETTINGS* aSettings) const override;
 
     void SetDefault() override
     {
         *m_ptr = m_default;
     }
 
-    bool MatchesFile( JSON_SETTINGS* aSettings ) const override
-    {
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            if( js->is_array() )
-            {
-                std::set<Type> val;
-
-                for( const auto& el : js->items() )
-                    val.insert( el.value().get<Type>() );
-
-                return val == *m_ptr;
-            }
-        }
-
-        return false;
-    }
+    bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
 
 protected:
     std::set<Type>* m_ptr;
     std::set<Type>  m_default;
 };
 
-extern template class APIVISIBLE PARAM_SET<wxString>;
-
 /**
  * Represents a list of strings holding directory paths.
  * Normalizes paths to unix directory separator style in the file.
  */
-class KICOMMON_API PARAM_PATH_LIST : public PARAM_LIST<wxString>
+class PARAM_PATH_LIST : public PARAM_LIST<wxString>
 {
 public:
     PARAM_PATH_LIST( const std::string& aJsonPath, std::vector<wxString>* aPtr,
@@ -714,60 +563,16 @@ public:
             m_default( aDefault )
     { }
 
-    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override
-    {
-        if( m_readOnly )
-            return;
+    void Load( JSON_SETTINGS* aSettings, bool aResetIfMissing = true ) const override;
 
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            if( js->is_object() )
-            {
-                m_ptr->clear();
-
-                for( const auto& el : js->items() )
-                    ( *m_ptr )[el.key()] = el.value().get<Value>();
-            }
-        }
-        else if( aResetIfMissing )
-            *m_ptr = m_default;
-    }
-
-    void Store( JSON_SETTINGS* aSettings) const override
-    {
-        nlohmann::json js( {} );
-
-        for( const auto& el : *m_ptr )
-            js[el.first] = el.second;
-
-        aSettings->Set<nlohmann::json>( m_path, js );
-    }
+    void Store( JSON_SETTINGS* aSettings) const override;
 
     virtual void SetDefault() override
     {
         *m_ptr = m_default;
     }
 
-    bool MatchesFile( JSON_SETTINGS* aSettings ) const override
-    {
-        if( std::optional<nlohmann::json> js = aSettings->GetJson( m_path ) )
-        {
-            if( js->is_object() )
-            {
-                if( m_ptr->size() != js->size() )
-                    return false;
-
-                std::map<std::string, Value> val;
-
-                for( const auto& el : js->items() )
-                    val[el.key()] = el.value().get<Value>();
-
-                return val == *m_ptr;
-            }
-        }
-
-        return false;
-    }
+    bool MatchesFile( JSON_SETTINGS* aSettings ) const override;
 
 private:
     std::map<std::string, Value>* m_ptr;
@@ -775,15 +580,10 @@ private:
 };
 
 
-extern template class APIVISIBLE PARAM_MAP<int>;
-extern template class APIVISIBLE PARAM_MAP<double>;
-extern template class APIVISIBLE PARAM_MAP<bool>;
-
-
 /**
  * A helper for <wxString, wxString> maps
  */
-class KICOMMON_API PARAM_WXSTRING_MAP : public PARAM_BASE
+class PARAM_WXSTRING_MAP : public PARAM_BASE
 {
 public:
     PARAM_WXSTRING_MAP( const std::string& aJsonPath, std::map<wxString, wxString>* aPtr,
diff --git a/kicad/pcm/pcm.h b/kicad/pcm/pcm.h
index 4ece4d3a56..c670943dcf 100644
--- a/kicad/pcm/pcm.h
+++ b/kicad/pcm/pcm.h
@@ -27,7 +27,6 @@
 #include <functional>
 #include <iostream>
 #include <map>
-#include <json_common.h>
 #include <nlohmann/json-schema.hpp>
 #include <thread>
 #include <tuple>
diff --git a/kicad/pcm/pcm_data.h b/kicad/pcm/pcm_data.h
index c8c8094925..3e56d18de8 100644
--- a/kicad/pcm/pcm_data.h
+++ b/kicad/pcm/pcm_data.h
@@ -24,7 +24,7 @@
 #include "core/wx_stl_compat.h"
 
 #include <map>
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 #include <optional>
 #include <string>
diff --git a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.cpp b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.cpp
index c8a778a80b..3c0325ebde 100644
--- a/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.cpp
+++ b/pcbnew/pcb_io/easyedapro/pcb_io_easyedapro.cpp
@@ -41,7 +41,7 @@
 #include <wx/zipstrm.h>
 #include <wx/log.h>
 
-#include <json_common.h>
+#include <nlohmann/json.hpp>
 #include <core/json_serializers.h>
 #include <core/map_helpers.h>
 #include <string_utf8_map.h>
diff --git a/thirdparty/json_schema_validator/CMakeLists.txt b/thirdparty/json_schema_validator/CMakeLists.txt
index 32e50c83f4..57d1d05dd0 100644
--- a/thirdparty/json_schema_validator/CMakeLists.txt
+++ b/thirdparty/json_schema_validator/CMakeLists.txt
@@ -6,8 +6,6 @@ add_library( nlohmann_json_schema_validator STATIC
     string-format-check.cpp
 )
 
-add_dependencies( nlohmann_json_schema_validator kicommon )
-
 target_include_directories( nlohmann_json_schema_validator
     PUBLIC
         $<INSTALL_INTERFACE:include>
@@ -16,5 +14,4 @@ target_include_directories( nlohmann_json_schema_validator
 
 target_link_libraries( nlohmann_json_schema_validator
     PUBLIC nlohmann_json
-    PRIVATE kicommon
 )
diff --git a/thirdparty/json_schema_validator/nlohmann/json-schema.hpp b/thirdparty/json_schema_validator/nlohmann/json-schema.hpp
index 582c113c1c..07befd3472 100644
--- a/thirdparty/json_schema_validator/nlohmann/json-schema.hpp
+++ b/thirdparty/json_schema_validator/nlohmann/json-schema.hpp
@@ -21,7 +21,6 @@
 #	define JSON_SCHEMA_VALIDATOR_API
 #endif
 
-#include <json_common.h>
 #include <nlohmann/json.hpp>
 
 #ifdef NLOHMANN_JSON_VERSION_MAJOR