diff --git a/src/language/ast/ASTModulesImporter.cpp b/src/language/ast/ASTModulesImporter.cpp
index 5ef3b58048d5a8c47ef9b773df4aaef490b5c06b..d52b964a8a670ca3af3d0bcd0f3223798e2502c3 100644
--- a/src/language/ast/ASTModulesImporter.cpp
+++ b/src/language/ast/ASTModulesImporter.cpp
@@ -37,7 +37,7 @@ ASTModulesImporter::_importAllModules(ASTNode& node)
 ASTModulesImporter::ASTModulesImporter(ASTNode& root_node) : m_symbol_table{*root_node.m_symbol_table}
 {
   Assert(root_node.is_root());
-  m_module_repository.populateCoreSymbolTable(root_node, m_symbol_table);
+  m_module_repository.populateMandatorySymbolTable(root_node, m_symbol_table);
 
   this->_importAllModules(root_node);
   std::cout << " - loaded modules\n";
diff --git a/src/language/modules/BuiltinModule.cpp b/src/language/modules/BuiltinModule.cpp
index 0ab7911394a9ebb81454c3381a380ea4aca9c03e..22d23f8033604698f44ea18e42c63e9ba48ba345 100644
--- a/src/language/modules/BuiltinModule.cpp
+++ b/src/language/modules/BuiltinModule.cpp
@@ -6,6 +6,8 @@
 
 #include <memory>
 
+BuiltinModule::BuiltinModule(bool is_mandatory) : m_is_mandatory{is_mandatory} {}
+
 void
 BuiltinModule::_addBuiltinFunction(const std::string& name,
                                    std::shared_ptr<IBuiltinFunctionEmbedder> builtin_function_embedder)
diff --git a/src/language/modules/BuiltinModule.hpp b/src/language/modules/BuiltinModule.hpp
index bf8743c9e5a9913dd6939e3d6cbe18495bccc27e..6ea3ee56ae6f4b8c3cbfd86ede3370a638d0bff4 100644
--- a/src/language/modules/BuiltinModule.hpp
+++ b/src/language/modules/BuiltinModule.hpp
@@ -18,7 +18,15 @@ class BuiltinModule : public IModule
 
   void _addTypeDescriptor(const ASTNodeDataType& type);
 
+  const bool m_is_mandatory;
+
  public:
+  bool
+  isMandatory() const final
+  {
+    return m_is_mandatory;
+  }
+
   const NameBuiltinFunctionMap&
   getNameBuiltinFunctionMap() const final
   {
@@ -31,7 +39,7 @@ class BuiltinModule : public IModule
     return m_name_type_map;
   }
 
-  BuiltinModule() = default;
+  BuiltinModule(bool is_mandatory = false);
 
   ~BuiltinModule() = default;
 };
diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index c9a214306e0b15ba4f10981dfd4c1125edbc1613..d3408934d649ffc625ad84c5bbe206a91f81555d 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -6,7 +6,7 @@
 #include <language/utils/BuiltinFunctionEmbedder.hpp>
 #include <utils/PugsUtils.hpp>
 
-CoreModule::CoreModule()
+CoreModule::CoreModule() : BuiltinModule(true)
 {
   this->_addBuiltinFunction("getPugsVersion", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>(
 
diff --git a/src/language/modules/IModule.hpp b/src/language/modules/IModule.hpp
index b839ed496d8d032f660a6d21c484c7ca342c5f98..48e4b15360de922a83025921d1058095cc205d89 100644
--- a/src/language/modules/IModule.hpp
+++ b/src/language/modules/IModule.hpp
@@ -19,6 +19,8 @@ class IModule
   IModule(IModule&&) = default;
   IModule& operator=(IModule&&) = default;
 
+  virtual bool isMandatory() const = 0;
+
   virtual const NameBuiltinFunctionMap& getNameBuiltinFunctionMap() const = 0;
 
   virtual const NameTypeMap& getNameTypeMap() const = 0;
diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp
index 1fff5dda8bba0203c033ccf4c8ab8afb6d93d8d8..13cc6f079c90d0ba2f621e6eb97ae04b0c830d52 100644
--- a/src/language/modules/ModuleRepository.cpp
+++ b/src/language/modules/ModuleRepository.cpp
@@ -13,6 +13,8 @@
 #include <language/utils/SymbolTable.hpp>
 #include <utils/PugsAssert.hpp>
 
+#include <algorithm>
+
 void
 ModuleRepository::_subscribe(std::unique_ptr<IModule> m)
 {
@@ -80,23 +82,18 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab
 }
 
 void
-ModuleRepository::populateCoreSymbolTable(const ASTNode& root_node, SymbolTable& symbol_table)
+ModuleRepository::populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table)
 {
-  const std::string& module_name = "core";
-
-  auto i_module = m_module_set.find(module_name);
-  if (i_module != m_module_set.end()) {
-    const IModule& populating_module = *i_module->second;
-
-    this->_populateEmbedderTableT(root_node, module_name, populating_module.getNameBuiltinFunctionMap(),
-                                  ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>(), symbol_table,
-                                  symbol_table.builtinFunctionEmbedderTable());
-
-    this->_populateEmbedderTableT(root_node, module_name, populating_module.getNameTypeMap(),
-                                  ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
-                                  symbol_table.typeEmbedderTable());
-  } else {
-    throw ParseError(std::string{"could not find module "} + module_name, std::vector{root_node.begin()});
+  for (auto&& [module_name, i_module] : m_module_set) {
+    if (i_module->isMandatory()) {
+      this->_populateEmbedderTableT(root_node, module_name, i_module->getNameBuiltinFunctionMap(),
+                                    ASTNodeDataType::build<ASTNodeDataType::builtin_function_t>(), symbol_table,
+                                    symbol_table.builtinFunctionEmbedderTable());
+
+      this->_populateEmbedderTableT(root_node, module_name, i_module->getNameTypeMap(),
+                                    ASTNodeDataType::build<ASTNodeDataType::type_name_id_t>(), symbol_table,
+                                    symbol_table.typeEmbedderTable());
+    }
   }
 }
 
@@ -104,9 +101,17 @@ std::string
 ModuleRepository::getAvailableModules() const
 {
   std::stringstream os;
-  os << rang::fgB::yellow << "Available modules" << rang::style::reset << '\n';
+  os << rang::fgB::yellow << "Available modules" << rang::fg::blue << " [modules tagged with a " << rang::style::reset
+     << rang::style::bold << '*' << rang::style::reset << rang::fg::blue << " are automatically imported]"
+     << rang::style::reset << '\n';
   for (auto& [name, i_module] : m_module_set) {
-    os << "  " << rang::fg::green << name << rang::style::reset << '\n';
+    if (i_module->isMandatory()) {
+      os << rang::style::bold << " *" << rang::style::reset;
+    } else {
+      os << "  ";
+    }
+    os << rang::fgB::green << name << rang::style::reset << '\n';
   }
+
   return os.str();
 }
diff --git a/src/language/modules/ModuleRepository.hpp b/src/language/modules/ModuleRepository.hpp
index b6983eb54988d630dcbdaee2d788a35b01ce748c..5a211f2bb7def2c0d983ebf994009b16044cbf7b 100644
--- a/src/language/modules/ModuleRepository.hpp
+++ b/src/language/modules/ModuleRepository.hpp
@@ -28,7 +28,7 @@ class ModuleRepository
 
  public:
   void populateSymbolTable(const ASTNode& module_name_node, SymbolTable& symbol_table);
-  void populateCoreSymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
+  void populateMandatorySymbolTable(const ASTNode& root_node, SymbolTable& symbol_table);
 
   std::string getAvailableModules() const;