diff --git a/.gitignore b/.gitignore
index d5e8be93414643c4e477e7c5bfe98cd931e0ac46..3f6f2bef9999988eb392af8140f1b5568cf2a74e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,6 @@ build/
 build.gcc/
 build.clang/
 bin/
-lektor/
 pkg/
 fake/
 *.out
@@ -22,3 +21,4 @@ fake/
 cscope.files
 cscope.out
 tags
+!*.inc
diff --git a/inc/lektor/.gitignore b/inc/lektor/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4e590e782720fdc68c237406971b0d0c7afd437a
--- /dev/null
+++ b/inc/lektor/.gitignore
@@ -0,0 +1,2 @@
+!*.inc
+!config.inc
diff --git a/inc/lektor/config.h b/inc/lektor/config.h
index 251d2e9ebdaef940c6e0c2f45fff1443162b945d..46f253801efd91f817b3044939000c867e90d80b 100644
--- a/inc/lektor/config.h
+++ b/inc/lektor/config.h
@@ -7,59 +7,13 @@
 /* Forward definition of the lkt_state structure */
 struct lkt_state;
 
+#define section(sct)    "\n[" sct "]\n"
+#define value(key, val) key " = " val "\n"
 static const char *const lkt_default_config_file =
-    "; Lektor's configuration file\n"
-    "; This file was generated, you may change it to your needs\n"
-    "\n"
-    "; Externals executables that may be called by lektord or any\n"
-    "; generated binary.\n"
-    "[externals]\n"
-    "mkvpropedit = /usr/bin/mkvpropedit\n"
-    "\n"
-    "; Server configuration.\n"
-    "[server]\n"
-    "host = 0.0.0.0      ; Listen any incomming connexions\n"
-    "port = 6600         ; Default MPD port\n"
-    "max_clients = 16    ; Maximun handled clients\n"
-    "\n"
-    "; Database configuration.\n"
-    "[database]\n"
-    "kara_dir = /home/kara                          ; Root for the mkv files\n"
-    "db_path  = /home/kara/kara.db                  ; Sqlite3 database, must be rw\n"
-    "\n"
-    "; Repo configuration.\n"
-    "[repo]\n"
-    "path = STATIC                                  ; The repo is a module\n"
-    "load_function = load_repo_https                ; But is compiled statically\n"
-    "name    = Kurisu                               ; A pretty name\n"
-    "url     = https://kurisu.iiens.net\n"
-    "json    = https://kurisu.iiens.net/api\n"
-    "id_json = https://kurisu.iiens.net/api?id=%ld\n"
-    "id_kara = https://kurisu.iiens.net/download.php?id=%ld\n"
-    "\n"
-    "; Player configuration, the window where the karas\n"
-    "; can be seen.\n"
-    "[player]\n"
-    "module = module_x11         ; Default module for the window\n"
-    "autoclear   = true          ; Clear the queue when starting\n"
-    "def_random  = false         ; Play at random per default\n"
-    "def_consume = false         ; Consume per default\n"
-    "def_single  = false         ; Single per default\n"
-    "def_repeat  = false         ; Repeat per default\n"
-    "font_size = 20              ; Size of the font in messages\n"
-    "font_name = Hack Nerd Font  ; I don't like Arial\n"
-    "msg_duration = 4            ; In seconds\n"
-    "\n"
-    "; The WinX11 module configuration. Modules are .so files\n"
-    "; loaded by lektor.\n"
-    "[module_x11]\n"
-    "path = LKT_PREFIX/lib/lektor/lib_module_x11.so\n"
-    "load_function = module_set_function\n"
-    "xwallpaper = false\n"
-    "\n"
-    "[module_sdl2]\n"
-    "path = LKT_PREFIX/lib/lektor/lib_module_sdl2.so\n"
-    "load_function = module_set_function\n";
+#include <lektor/config.inc>
+;
+#undef value
+#undef section
 
 /* It is just an alias to the consecutive use of config_detect_file and
    config_new function, with the return an '&&' between the two returns of the
diff --git a/inc/lektor/config.inc b/inc/lektor/config.inc
new file mode 100644
index 0000000000000000000000000000000000000000..35f4b1bf132d8eff07aee3f3749debc968bc3529
--- /dev/null
+++ b/inc/lektor/config.inc
@@ -0,0 +1,32 @@
+section("externals")
+value("mkvpropedit",    "/usr/bin/mkvpropedit")
+
+section("server")
+value("host",           "0.0.0.0")
+value("port",           "6600")
+value("max_clients",    "16")
+
+section("database")
+value("kara_dir",       "/home/kara")
+value("db_path",        "/home/kara/kara.db")
+
+section("repo")
+value("path",           "STATIC")
+value("load_function",  "load_repo_https")
+value("name",           "Kurisu")
+value("url",            "https://kurisu.iiens.net")
+value("json",           "https://kurisu.iiens.net/api")
+value("id_json",        "https://kurisu.iiens.net/api?id=%ld")
+value("id_kara",        "https://kurisu.iiens.net/download.php?id=%ld")
+
+section("player")
+value("path",           "STATIC")
+value("load_function",  "load_sdl2")
+value("autoclear",      "true")
+value("def_random",     "false")
+value("def_consume",    "false")
+value("def_single",     "false")
+value("def_repeat",     "false")
+value("font_size",      "20")
+value("font_name",      "Hack Nerd Font")
+value("msg_duration",   "4")
diff --git a/inc/lektor/reg.h b/inc/lektor/reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..970fc1b2e582c61c721d3654a17ea9c4f6ddd708
--- /dev/null
+++ b/inc/lektor/reg.h
@@ -0,0 +1,24 @@
+#pragma once
+
+struct lkt_state;
+
+/* Store functions with a name, so that all the lib will have acces to it
+   with a name that can be generated or red from a config file. */
+struct module_reg {
+    const char *name;
+    int (*func)(void *, struct lkt_state *, void *);
+};
+
+extern struct module_reg *reg;
+
+#define REG_BEGIN(reg)  struct module_reg reg[] = {
+#define REG_ADD(__func) { .name = #__func,  .func = __func  },
+#define REG_END()       { .name = NULL,     .func = NULL    } };
+
+/* If handle is NULL, file is unused and the reg is red. Otherwise,
+   we use dlfcn to search for the symbol which is returned. If *handle
+   is NULL, it will be created by opening the file. */
+void *reg_pick(const char *file, void **handle, const char *symbol);
+
+/* Set the ref for this .a / .so file */
+void reg_set(struct module_reg *);
diff --git a/src/config.c b/src/config.c
index 44008e7d79b0928a38a15265651f441fc31e8355..9bc21ea8f00e685c1167c61746b89ebb97021935 100644
--- a/src/config.c
+++ b/src/config.c
@@ -151,34 +151,17 @@ load_module_by_name(struct lkt_state *srv, const char *name, void *mod)
 inline static int
 validate_conf(volatile sqlite3 *db)
 {
-#define CHK_OPTION(section, name)                                               \
+    const char *section;
+#define section(_sct) section = _sct;
+#define value(name, value)                                                      \
     if (!database_config_exists(db, section, name)) {                           \
-        LOG_ERROR("%s", "Missing option \""name"\" in section \""section"\"");  \
+        LOG_ERROR_SCT("CONFIG", "Missing option \""name"\" in section \"%s\"",  \
+                      section);                                                 \
         return 1;                                                               \
     }
-
-    CHK_OPTION("externals", "mkvpropedit");
-
-    CHK_OPTION("server", "host");
-    CHK_OPTION("server", "port");
-    CHK_OPTION("server", "max_clients");
-
-    CHK_OPTION("database", "kara_dir");
-    CHK_OPTION("database", "db_path");
-
-    CHK_OPTION("repo", "name");
-    CHK_OPTION("repo", "url");
-    CHK_OPTION("repo", "json");
-    CHK_OPTION("repo", "id_json");
-    CHK_OPTION("repo", "id_kara");
-
-    CHK_OPTION("player", "autoclear");
-    CHK_OPTION("player", "def_random");
-    CHK_OPTION("player", "def_consume");
-    CHK_OPTION("player", "def_single");
-    CHK_OPTION("player", "def_repeat");
-    CHK_OPTION("player", "module");
-#undef CHK_OPTION
+#include <lektor/config.inc>
+#undef section
+#undef value
 
     return 0;
 }
diff --git a/src/net/listen.c b/src/net/listen.c
index a0ab1f1f0e7c96de18db6e17d5377f388d5523bf..3fab03bbf24716fdb3966c8f43501e8552eca28b 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -741,8 +741,8 @@ lkt_listen(void)
     if (autoclear)
         database_queue_clear(srv.db);
 
-    RETURN_IF(load_module_by_name(&srv, mod,    &srv.win),  "Can't load module player", 3);
-    RETURN_IF(load_module_by_name(&srv, "repo", &srv.repo), "Can't load module repo", 3);
+    RETURN_IF(load_module_by_name(&srv, "player", &srv.win),  "Can't load module player", 3);
+    RETURN_IF(load_module_by_name(&srv, "repo",   &srv.repo), "Can't load module repo", 3);
 
     for (;;) {
         if (handle_network_events(&srv) < 0)