diff --git a/applications/gui2/src/main.cpp b/applications/gui2/src/main.cpp
index 0a7eeccb2e5bca68a9e33e4a5a8bae43ecca348d..500baaca32287a84f9080ea5984a5c446154750a 100644
--- a/applications/gui2/src/main.cpp
+++ b/applications/gui2/src/main.cpp
@@ -174,5 +174,7 @@ int main(int argc, char **argv) {
 	ftl::pool.stop(true);
 	LOG(INFO) << "All threads stopped.";
 
+	ftl::config::cleanup();
+
 	return 0;
 }
diff --git a/applications/vision/src/main.cpp b/applications/vision/src/main.cpp
index 9f9b8d84855883454f029af5b6b9027d37c23e09..709c08d48e14cce46f116c2c83bd15dfd098e249 100644
--- a/applications/vision/src/main.cpp
+++ b/applications/vision/src/main.cpp
@@ -297,6 +297,9 @@ int main(int argc, char **argv) {
 	run(root);
 
 	delete root;
+
+	ftl::config::cleanup();
+
 	LOG(INFO) << "Terminating with code " << ftl::exit_code;
 	LOG(INFO) << "Branch: " << ftl::branch_name;
 	return ftl::exit_code;
diff --git a/components/common/cpp/include/ftl/configurable.hpp b/components/common/cpp/include/ftl/configurable.hpp
index 1c157ba601c01a1bb8cb01df5eddfd07b60b6269..c32b3dce434a3b93ddb60b1a71841d60825ed3c8 100644
--- a/components/common/cpp/include/ftl/configurable.hpp
+++ b/components/common/cpp/include/ftl/configurable.hpp
@@ -12,6 +12,7 @@
 #include <list>
 #include <functional>
 #include <optional>
+#include <unordered_set>
 
 #define REQUIRED(...) required(__func__, __VA_ARGS__)
 
@@ -102,12 +103,37 @@ class Configurable {
 	 */
 	virtual void refresh();
 
+	/**
+	 * Restore configurable properties from session storage using this key.
+	 * The key could be the same as configurable ID or perhaps uses another
+	 * property such as URI. If restore is used it will also result in a save
+	 * when the configurable is destroyed. The key should ideally be unique.
+	 * 
+	 * The allowed parameter specifies the set of properties that can be saved.
+	 */
+	void restore(const std::string &key, const std::unordered_set<std::string> &allowed);
+
+	/**
+	 * Load defaults from config file. The key represents type information and
+	 * many configurables can load from the same key. If load defaults has been
+	 * used by the configurable, then it is also called again when the
+	 * configurable is reset.
+	 */
+	void loadDefaults(const std::string &key);
+
+	virtual void reset() {};
+
+	void save();
+
 	protected:
 	nlohmann::json *config_;
 
 	virtual void inject(const std::string &name, nlohmann::json &value) {}
 
 	private:
+	std::string restore_;
+	std::string defaults_;
+	std::unordered_set<std::string> save_allowed_;
 	std::map<std::string, std::list<std::function<void(const config::Event&)>>> observers_; 
 
 	void _trigger(const std::string &name);
diff --git a/components/common/cpp/include/ftl/configuration.hpp b/components/common/cpp/include/ftl/configuration.hpp
index 5b0106fe0dbc15e8cb3cefbbb7b08630d52d5098..79a5b540322a376799c721eb2f987dd3d10a1325 100644
--- a/components/common/cpp/include/ftl/configuration.hpp
+++ b/components/common/cpp/include/ftl/configuration.hpp
@@ -42,6 +42,9 @@ Configurable *configure(int argc, char **argv, const std::string &root);
 
 Configurable *configure(json_t &);
 
+nlohmann::json &getRestore(const std::string &key);
+nlohmann::json &getDefault(const std::string &key);
+
 void cleanup();
 
 void removeConfigurable(Configurable *cfg);
diff --git a/components/common/cpp/src/configurable.cpp b/components/common/cpp/src/configurable.cpp
index 5791980d43c384a6b3f751b4dc8028e902cf5357..6ded7367f6e28492c501351069c0bd570d96a069 100644
--- a/components/common/cpp/src/configurable.cpp
+++ b/components/common/cpp/src/configurable.cpp
@@ -26,9 +26,29 @@ Configurable::Configurable(nlohmann::json &config) : config_(&config) {
 }
 
 Configurable::~Configurable() {
+	save();
 	ftl::config::removeConfigurable(this);
 }
 
+void Configurable::save() {
+	if (restore_.size() > 0) {
+		auto &r = ftl::config::getRestore(restore_);
+		for (auto &i : save_allowed_) {
+			r[i] = (*config_)[i];
+		}
+	}
+}
+
+void Configurable::restore(const std::string &key, const std::unordered_set<std::string> &allowed) {
+	auto &r = ftl::config::getRestore(key);
+	if (r.is_object()) {
+		config_->merge_patch(r);
+		
+	}
+	restore_ = key;
+	save_allowed_ = allowed;
+}
+
 template <typename T>
 T ftl::Configurable::value(const std::string &name, const T &def) {
 	auto r = get<T>(name);
diff --git a/components/common/cpp/src/configuration.cpp b/components/common/cpp/src/configuration.cpp
index 9c1154d6e63e88c80197b12b6d681b0a29c7ac30..aba5beede2a9fd37c56c977f49acf794f6442b0b 100644
--- a/components/common/cpp/src/configuration.cpp
+++ b/components/common/cpp/src/configuration.cpp
@@ -236,11 +236,25 @@ static bool mergeConfig(const string path) {
 	}
 }
 
+static MUTEX mutex;
 static std::map<std::string, json_t*> config_index;
 static std::map<std::string, ftl::Configurable*> config_instance;
 static std::map<std::string, ftl::Configurable*> config_alias;
 static std::map<std::string, std::vector<ftl::Configurable*>> tag_index;
 
+static nlohmann::json config_restore;
+static nlohmann::json config_defaults;
+
+nlohmann::json &ftl::config::getRestore(const std::string &key) {
+	UNIQUE_LOCK(mutex, lk);
+	return config_restore[key];
+}
+
+nlohmann::json &ftl::config::getDefault(const std::string &key) {
+	UNIQUE_LOCK(mutex, lk);
+	return config_defaults[key];
+}
+
 /*
  * Recursively URI index the JSON structure.
  */
@@ -640,19 +654,27 @@ Configurable *ftl::config::configure(ftl::config::json_t &cfg) {
 	return rootcfg;
 }
 
-static bool doing_cleanup = false;
+static std::atomic_bool doing_cleanup = false;
 void ftl::config::cleanup() {
 	if (doing_cleanup) return;
 	doing_cleanup = true;
+
+	//UNIQUE_LOCK(mutex, lk);
+
 	for (auto f : config_instance) {
-		delete f.second;
+		//delete f.second;
+		f.second->save();
 	}
 	config_instance.clear();
+
+	ftl::saveJSON(FTL_LOCAL_CONFIG_ROOT "/session.json", config_restore);
+
 	doing_cleanup = false;
 }
 
 void ftl::config::removeConfigurable(Configurable *cfg) {
 	if (doing_cleanup) return;
+	UNIQUE_LOCK(mutex, lk);
 
 	auto i = config_instance.find(cfg->getID());
 	if (i != config_instance.end()) {
@@ -821,6 +843,8 @@ Configurable *ftl::config::configure(int argc, char **argv, const std::string &r
 	if (options.find("id") != options.end()) config["$id"] = nlohmann::json::parse(options["id"]).get<string>();
 	_indexConfig(config);
 
+	config_restore = std::move(ftl::loadJSON(FTL_LOCAL_CONFIG_ROOT "/session.json"));
+
 	Configurable *rootcfg = create<Configurable>(config);
 	if (root_str.size() > 0) {
 		LOG(INFO) << "Setting root to " << root_str;
diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp
index a1d3babd61a23627fd6f1582f7cdf7acd52eb3e0..baa9b1e3dfefbf302783417738b91aac98c81a60 100644
--- a/components/streams/src/feed.cpp
+++ b/components/streams/src/feed.cpp
@@ -22,7 +22,7 @@
 using ftl::stream::Feed;
 using ftl::codecs::Channel;
 
-static nlohmann::json feed_config;
+//static nlohmann::json feed_config;
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -61,7 +61,10 @@ Feed::Filter &Feed::Filter::select(const std::unordered_set<ftl::codecs::Channel
 Feed::Feed(nlohmann::json &config, ftl::net::Universe*net) :
 		ftl::Configurable(config), net_(net) {
 
-	feed_config = ftl::loadJSON(FTL_LOCAL_CONFIG_ROOT "/feed.json");
+	//feed_config = ftl::loadJSON(FTL_LOCAL_CONFIG_ROOT "/feed.json");
+	restore(ftl::Configurable::getID(), {
+		"recent_files"
+	});
 
 	pool_ = std::make_unique<ftl::data::Pool>(3,5);
 
@@ -159,7 +162,7 @@ Feed::Feed(nlohmann::json &config, ftl::net::Universe*net) :
 
 Feed::~Feed() {
 	std::unique_lock<std::mutex> lk(mtx_);
-	ftl::saveJSON(FTL_LOCAL_CONFIG_ROOT "/feed.json", feed_config);
+	//ftl::saveJSON(FTL_LOCAL_CONFIG_ROOT "/feed.json", feed_config);
 
 	receiver_.reset();  // Note: Force destruction first to remove filters this way
 
@@ -331,7 +334,7 @@ std::vector<std::string> Feed::availableNetworkSources() {
 
 std::vector<std::string> Feed::availableFileSources() {
 	std::vector<std::string> files;
-	auto &recent_files = feed_config["recent_files"];
+	auto &recent_files = getConfig()["recent_files"];
 
 	for (auto &f : recent_files.items()) {
 		files.push_back(f.key());
@@ -371,7 +374,7 @@ std::string Feed::getName(const std::string &puri) {
 	} else if (uri.getScheme() == ftl::URI::SCHEME_DEVICE) {
 		return "Device";
 	} else if (uri.getScheme() == ftl::URI::SCHEME_FILE) {
-		return feed_config["recent_files"][uri.getBaseURI()].value("name", "FTLFile");
+		return getConfig()["recent_files"][uri.getBaseURI()].value("name", "FTLFile");
 	}
 
 	return "No Name";
@@ -422,7 +425,7 @@ uint32_t Feed::add(const std::string &path) {
 
 		fstream->set("uri", path);
 
-		auto &recent_files = feed_config["recent_files"];
+		auto &recent_files = getConfig()["recent_files"];
 		auto &file_details = recent_files[uri.getBaseURI()];
 		std::string fname = uri.getPathSegment(-1);
 		file_details["name"] = fname.substr(0, fname.find_last_of('.'));
diff --git a/components/streams/src/renderer.cpp b/components/streams/src/renderer.cpp
index 3e88b942302fe7b4f21af77de44209052d5e6f46..a9f80db5e27f7210be196a4aa6a230c610de284e 100644
--- a/components/streams/src/renderer.cpp
+++ b/components/streams/src/renderer.cpp
@@ -11,6 +11,11 @@ using ftl::rgbd::Capability;
 
 Source::Source(nlohmann::json &config, ftl::stream::Feed *feed)
 : ftl::Configurable(config), feed_(feed) {
+	restore("device:render", {
+		"renderer",
+		"source",
+		"intrinsics"
+	});
 
 	renderer_ = std::unique_ptr<ftl::render::CUDARender>(
 		ftl::create<ftl::render::CUDARender>(this, "renderer")