diff --git a/loader/include/Geode/loader/Setting.hpp b/loader/include/Geode/loader/Setting.hpp
index 0d203e03..30efd6e6 100644
--- a/loader/include/Geode/loader/Setting.hpp
+++ b/loader/include/Geode/loader/Setting.hpp
@@ -9,6 +9,7 @@
 #include <Geode/utils/JsonValidation.hpp>
 #include <Geode/utils/convert.hpp>
 #include <Geode/utils/platform.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <regex>
 
 #pragma warning(push)
@@ -266,7 +267,7 @@ namespace geode {
                     value = static_cast<Class*>(this)->getDefault();
                     return Err(
                         "Value must be one of " +
-                        utils::container::join(m_oneOf.value(), ", ")
+                        utils::ranges::join(m_oneOf.value(), ", ")
                     );
                 }
                 return Ok();
diff --git a/loader/include/Geode/utils/container.hpp b/loader/include/Geode/utils/container.hpp
index 411feff6..d2faf9ae 100644
--- a/loader/include/Geode/utils/container.hpp
+++ b/loader/include/Geode/utils/container.hpp
@@ -12,6 +12,7 @@ namespace geode::utils::container {
      * @returns True if element is in `vec`, false if not.
      */
     template<class C, class T>
+    [[deprecated("Use geode::utils::ranges::contains instead")]]
     bool contains(C const& cont, T const& elem) {
         return std::find(cont.begin(), cont.end(), elem) != cont.end();
     }
@@ -25,6 +26,7 @@ namespace geode::utils::container {
      * in `vec`, false if not.
      */
     template<class C, class T>
+    [[deprecated("Use geode::utils::ranges::contains instead")]]
     bool contains(C const& cont, std::function<bool(T)> containFunc) {
         for (auto const& item : cont) {
             if (containFunc(item))
@@ -41,6 +43,7 @@ namespace geode::utils::container {
      * @returns Joined string.
      */
     template<class C>
+    [[deprecated("Use geode::utils::ranges::join instead")]]
     std::string join(C const& cont, std::string const& sep) {
         std::string res = "";
         bool first = true;
@@ -67,6 +70,7 @@ namespace geode::utils::container {
      * @returns Mapped container.
      */
     template<class C, class C2, class T, class T2>
+    [[deprecated("Use geode::utils::ranges::map instead")]]
     C2 map(C const& cont, std::function<T2(T)> mapFunc) {
         C2 res;
         std::transform(cont.begin(), cont.end(), res.end(), mapFunc);
diff --git a/loader/include/Geode/utils/ranges.hpp b/loader/include/Geode/utils/ranges.hpp
new file mode 100644
index 00000000..ed7e0471
--- /dev/null
+++ b/loader/include/Geode/utils/ranges.hpp
@@ -0,0 +1,143 @@
+#pragma once
+
+#include <Geode/DefaultInclude.hpp>
+#include <string>
+#include <algorithm>
+
+namespace geode::utils::ranges {
+    template<class C>
+    concept ValidConstContainer = requires(C const& c) {
+        c.begin();
+        c.end();
+        typename C::value_type;
+    };
+
+    template<class C>
+    concept ValidMutContainer = requires(C& c) {
+        c.begin();
+        c.end();
+        typename C::value_type;
+    };
+
+    template<class C>
+    concept ValidContainer = ValidConstContainer<C> && ValidMutContainer<C>;
+
+    template<class P, class C>
+    concept ValidCUnaryPredicate = requires(P p, typename C::value_type const& t) {
+        { p(t) } -> std::convertible_to<bool>;
+    };
+
+    template<class P, class From, class Into>
+    concept ValidIntoConverter = requires(P p, From const& t) {
+        { p(t) } -> std::convertible_to<Into>;
+    };
+
+    template<ValidConstContainer C>
+    bool contains(C const& cont, typename C::value_type const& elem) {
+        return std::find(cont.begin(), cont.end(), elem) != cont.end();
+    }
+
+    template<ValidConstContainer C, ValidCUnaryPredicate<C> Predicate>
+    bool contains(C const& cont, Predicate fun) {
+        return std::find_if(cont.begin(), cont.end(), fun) != cont.end();
+    }
+
+    template<ValidConstContainer C, class Output>
+        requires
+            std::is_default_constructible_v<Output> &&
+            std::is_convertible_v<Output, typename C::value_type>
+    Output join(C const& cont, Output const& separator) {
+        auto res = Output();
+        bool first = true;
+        for (auto& p : cont) {
+            if (!first) {
+                res += separator;
+            } else {
+                first = false;
+            }
+            res += p;
+        }
+        return res;
+    }
+
+    template<ValidConstContainer C>
+    std::string join(C const& cont, std::string const& separator) {
+        auto res = std::string();
+        bool first = true;
+        for (auto& p : cont) {
+            if (!first) {
+                res += separator;
+            } else {
+                first = false;
+            }
+            res += p;
+        }
+        return res;
+    }
+
+    template<
+        ValidConstContainer C,
+        class Output,
+        ValidIntoConverter<typename C::value_type, Output> Conv
+    >
+        requires
+            std::is_default_constructible_v<Output>
+    Output join(C const& cont, Output const& separator, Conv converter) {
+        auto res = Output();
+        bool first = true;
+        for (auto& p : cont) {
+            if (!first) {
+                res += separator;
+            } else {
+                first = false;
+            }
+            res += Conv(p);
+        }
+        return res;
+    }
+
+    template<ValidContainer C>
+    C& push(C& container, C const& toAdd) {
+        container.insert(container.end(), toAdd.begin(), toAdd.end());
+        return container;
+    }
+
+    template<ValidMutContainer C>
+    C& remove(C& container, typename C::value_type const& value) {
+        container.erase(
+            std::remove(container.begin(), container.end(), value),
+            container.end()
+        );
+        return container;
+    }
+
+    template<ValidContainer C, ValidCUnaryPredicate<C> Predicate>
+    C filter(C const& container, Predicate filterFun) {
+        auto res = C();
+        std::copy_if(container.begin(), container.end(), res.end(), filterFun);
+        return res;
+    }
+
+    template<class R, ValidConstContainer C, class Reducer>
+        requires requires(Reducer r, R& acc, typename C::value_type t) {
+            { r(acc, t) } -> std::same_as<void>;
+        }
+    R reduce(C const& container, Reducer reducer) {
+        auto res = R();
+        for (auto& item : container) {
+            reducer(res, item);
+        }
+        return res;
+    }
+    
+    template<
+        ValidConstContainer From,
+        ValidContainer Into,
+        ValidIntoConverter<typename From::value_type, typename Into::value_type> Mapper
+    >
+    Into map(From const& from, Mapper mapper) {
+        auto res = Into();
+        std::transform(from.begin(), from.end(), res.end(), mapper);
+        return res;
+    }
+}
diff --git a/loader/include/Geode/utils/vector.hpp b/loader/include/Geode/utils/vector.hpp
index 003b5144..f9919fbf 100644
--- a/loader/include/Geode/utils/vector.hpp
+++ b/loader/include/Geode/utils/vector.hpp
@@ -14,7 +14,8 @@ namespace geode::utils::vector {
      * @returns True if element is in `vec`, false if not.
      */
     template<class T>
-    bool contains(gd::vector<T> const& vec, T const& elem) {
+    [[deprecated("Use geode::utils::ranges::contains instead")]]
+    bool contains(std::vector<T> const& vec, T const& elem) {
         return std::find(vec.begin(), vec.end(), elem) != vec.end();
     }
 
@@ -23,10 +24,11 @@ namespace geode::utils::vector {
      * @param vec The vector to check.
      * @param elem The element to get the index of.
      * @returns Iterator to the index of element, or 
-     * gd::vector::end if the item is not in the vector.
+     * std::vector::end if the item is not in the vector.
      */
     template<class T>
-    typename gd::vector<T>::const_iterator indexOf(gd::vector<T> const& vec, T const& elem) {
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    typename std::vector<T>::const_iterator indexOf(std::vector<T> const& vec, T const& elem) {
         return std::find(vec.begin(), vec.end(), elem);
     }
 
@@ -39,7 +41,8 @@ namespace geode::utils::vector {
      * in `vec`, false if not.
      */
     template<class T>
-    bool contains(gd::vector<T> const& vec, std::function<bool(T)> containFunc) {
+    [[deprecated("Use geode::utils::ranges::contains instead")]]
+    bool contains(std::vector<T> const& vec, std::function<bool(T)> containFunc) {
         for (auto const& item : vec) {
             if (containFunc(item))
                 return true;
@@ -53,7 +56,8 @@ namespace geode::utils::vector {
      * @param subVec The vector to add.
      */
     template<class T>
-    void push(gd::vector<T> & vec, gd::vector<T> const& subVec) {
+    [[deprecated("Use geode::utils::ranges::push instead")]]
+    void push(std::vector<T> & vec, std::vector<T> const& subVec) {
         vec.insert(vec.begin(), subVec.begin(), subVec.end());
     }
 
@@ -65,7 +69,8 @@ namespace geode::utils::vector {
      * @returns Joined string.
      */
     template<class T>
-    std::string join(gd::vector<T> const& vec, std::string const& sep) {
+    [[deprecated("Use geode::utils::ranges::join instead")]]
+    std::string join(std::vector<T> const& vec, std::string const& sep) {
         std::string res = "";
 
         for (auto p : vec) {
@@ -89,8 +94,9 @@ namespace geode::utils::vector {
      * @returns Mapped vector.
      */
     template<class T, class T2>
-    gd::vector<T2> map(gd::vector<T> const& vec, std::function<T2(T)> mapFunc) {
-        gd::vector<T2> res;
+    [[deprecated("Use geode::utils::ranges::map instead")]]
+    std::vector<T2> map(std::vector<T> const& vec, std::function<T2(T)> mapFunc) {
+        std::vector<T2> res;
         std::transform(vec.begin(), vec.end(), res.end(), mapFunc);
         return res;
     }
@@ -104,8 +110,9 @@ namespace geode::utils::vector {
      * @returns Filtered vector.
      */
     template<class T>
-    gd::vector<T>& filterIP(gd::vector<T> & vec, std::function<bool(T)> filterFunc) {
-        gd::vector<T> res;
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    std::vector<T>& filterIP(std::vector<T> & vec, std::function<bool(T)> filterFunc) {
+        std::vector<T> res;
         for (auto m : vec) {
             if (filterFunc(m)) {
                 res.push_back(m);
@@ -124,8 +131,9 @@ namespace geode::utils::vector {
      * @returns Filtered vector.
      */
     template<class T>
-    gd::vector<T> filter(gd::vector<T> const& vec, std::function<bool(T)> filterFunc) {
-        gd::vector<T> res;
+    [[deprecated("Use geode::utils::ranges::filter instead")]]
+    std::vector<T> filter(std::vector<T> const& vec, std::function<bool(T)> filterFunc) {
+        std::vector<T> res;
         for (auto m : vec) {
             if (filterFunc(m)) {
                 res.push_back(m);
@@ -145,7 +153,8 @@ namespace geode::utils::vector {
      * found, the return type is nullptr.
      */
     template<class T>
-    T select(gd::vector<T> const& vec, std::function<bool(T)> selectFunc) {
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    T select(std::vector<T> const& vec, std::function<bool(T)> selectFunc) {
         for (auto const& v : vec) {
             if (selectFunc(v)) {
                 return v;
@@ -165,7 +174,8 @@ namespace geode::utils::vector {
      * @returns Filtered vector.
      */
     template<class T>
-    gd::vector<T> selectAll(gd::vector<T> const& vec, std::function<bool(T)> selectFunc) {
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    std::vector<T> selectAll(std::vector<T> const& vec, std::function<bool(T)> selectFunc) {
         return filter<T>(vec, selectFunc);
     }
 
@@ -176,7 +186,8 @@ namespace geode::utils::vector {
      * @returns Reference to vector.
      */
     template<class T>
-    gd::vector<T>& erase(gd::vector<T>& vec, T const& element) {
+    [[deprecated("Use geode::utils::ranges::remove instead")]]
+    std::vector<T>& erase(std::vector<T>& vec, T const& element) {
         vec.erase(std::remove(vec.begin(), vec.end(), element), vec.end());
         return vec;
     }
@@ -189,7 +200,8 @@ namespace geode::utils::vector {
      * @returns Reference to vector.
      */
     template<class T>
-    gd::vector<T>& erase(gd::vector<T>& vec, std::function<bool(T)> eraseFunc) {
+    [[deprecated("Use geode::utils::ranges::remove instead")]]
+    std::vector<T>& erase(std::vector<T>& vec, std::function<bool(T)> eraseFunc) {
         vec.erase(std::remove_if(vec.begin(), vec.end(), eraseFunc), vec.end());
         return vec;
     }
@@ -204,7 +216,7 @@ namespace geode::utils::vector {
      * accumulator, for example with R += T, to
      * compute the reduced value.
      * @example ```cpp
-     * gd::vector<int> numbers = { 1, 3, 7, 8, };
+     * std::vector<int> numbers = { 1, 3, 7, 8, };
      * int total = reduce<int, int>(numbers, [](int& acc, int val) -> void {
      *      acc += val;
      * }); // 19
@@ -212,7 +224,8 @@ namespace geode::utils::vector {
      * @returns Reduced value.
      */
     template<class R, class T>
-    R reduce(gd::vector<T> const& vec, std::function<void(R&, T)> reduceFunc) {
+    [[deprecated("Use geode::utils::ranges::reduce instead")]]
+    R reduce(std::vector<T> const& vec, std::function<void(R&, T)> reduceFunc) {
         R res = R();
         for (auto const& item : vec) {
             reduceFunc(res, item);
@@ -228,7 +241,8 @@ namespace geode::utils::vector {
      * @param after Element to insert before.
      */
     template<class T>
-    void insertBefore(gd::vector<T> & vec, T const& item, T const& before) {
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    void insertBefore(std::vector<T> & vec, T const& item, T const& before) {
         vec.insert(utils::vector::indexOf(vec, before), item);
     }
 
@@ -240,7 +254,8 @@ namespace geode::utils::vector {
      * @param after Element to insert after.
      */
     template<class T>
-    void insertAfter(gd::vector<T> & vec, T const& item, T const& after) {
+    [[deprecated("Useless utility, if you want it added to geode::utils::ranges open an Issue on GitHub")]]
+    void insertAfter(std::vector<T> & vec, T const& item, T const& after) {
         vec.insert(utils::vector::indexOf(vec, after) + 1, item);
     }
 }
diff --git a/loader/src/index/Index.cpp b/loader/src/index/Index.cpp
index a2b0a018..5b0037b4 100644
--- a/loader/src/index/Index.cpp
+++ b/loader/src/index/Index.cpp
@@ -9,6 +9,7 @@
 #include <Geode/utils/vector.hpp>
 #include <Geode/utils/map.hpp>
 #include <Geode/utils/general.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <Geode/loader/Loader.hpp>
 #include <Geode/loader/Mod.hpp>
 #include <Geode/binding/FLAlertLayer.hpp>
@@ -447,7 +448,7 @@ Result<InstallHandle> Index::installItems(
         if (!list) {
             return Err(list.error());
         }
-        utils::vector::push(ids, list.value());
+        ranges::push(ids, list.value());
     }
     auto ret = std::make_shared<InstallItems>(
         std::unordered_set(ids.begin(), ids.end())
@@ -617,7 +618,7 @@ void InstallItems::finish(bool replaceFiles) {
         FLAlertLayer::create(
             "Mods installed",
             "The following <cy>mods</c> have been installed: " + 
-            container::join(m_toInstall, ",") + "\n"
+            ranges::join(m_toInstall, std::string(",")) + "\n"
             "Please <cr>restart the game</c> to apply",
             "OK"
         )->show();
diff --git a/loader/src/load/Hook.cpp b/loader/src/load/Hook.cpp
index 70b9c248..135bd330 100644
--- a/loader/src/load/Hook.cpp
+++ b/loader/src/load/Hook.cpp
@@ -4,6 +4,7 @@
 #include <Geode/loader/Loader.hpp>
 #include <Geode/utils/casts.hpp>
 #include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
 // #include <hook/hook.hpp>
 #include <Geode/hook-core/Hook.hpp>
 #include "InternalLoader.hpp"
@@ -60,7 +61,7 @@ Result<> Mod::disableHook(Hook* hook) {
 Result<> Mod::removeHook(Hook* hook) {
     auto res = this->disableHook(hook);
     if (res) {
-        utils::vector::erase<Hook*>(this->m_hooks, hook);
+        ranges::remove(m_hooks, hook);
         delete hook;
     }
     return res;
diff --git a/loader/src/load/Loader.cpp b/loader/src/load/Loader.cpp
index 48d26034..39a13a41 100644
--- a/loader/src/load/Loader.cpp
+++ b/loader/src/load/Loader.cpp
@@ -6,7 +6,7 @@
 #include <InternalMod.hpp>
 #include <Geode/utils/file.hpp>
 #include <Geode/utils/conststring.hpp>
-#include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <Geode/utils/map.hpp>
 #include <Geode/utils/types.hpp>
 #include <mutex>
@@ -41,7 +41,7 @@ void Loader::createDirectories() {
     ghc::filesystem::create_directory(logDir);
     ghc::filesystem::create_directory(tempDir);
 
-    if (!utils::vector::contains(m_modDirectories, modDir)) {
+    if (!ranges::contains(m_modDirectories, modDir)) {
         m_modDirectories.push_back(modDir);
     }
 
@@ -388,12 +388,7 @@ void Loader::pushLog(log::Log&& log) {
 }
 
 void Loader::popLog(log::Log* log) {
-    /*for (auto i = m_logs.begin(); i < m_logs.end(); ++i) {
-        if (i == log) {
-            m_logs.erase(i);
-        }
-    }*/
-    utils::vector::erase(m_logs, *log);
+    ranges::remove(m_logs, *log);
 }
 
 std::vector<log::Log*> Loader::getLogs(
@@ -402,9 +397,7 @@ std::vector<log::Log*> Loader::getLogs(
     std::vector<log::Log*> logs;
 
     for (auto& log : m_logs) {
-        if (utils::vector::contains<Severity>(
-            severityFilter, log.getSeverity()
-        ) || !severityFilter.size()) {
+        if (ranges::contains(severityFilter, log.getSeverity()) || !severityFilter.size()) {
             logs.push_back(&log);
         }
     }
diff --git a/loader/src/load/Mod.cpp b/loader/src/load/Mod.cpp
index 0d2504c0..e973d005 100644
--- a/loader/src/load/Mod.cpp
+++ b/loader/src/load/Mod.cpp
@@ -10,6 +10,7 @@
 #include <Geode/utils/map.hpp>
 #include <Geode/utils/string.hpp>
 #include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <InternalMod.hpp>
 #include <ZipUtils.h>
 
@@ -519,9 +520,9 @@ std::vector<Hook*> Mod::getHooks() const {
 }
 
 bool Mod::depends(std::string const& id) const {
-    return utils::vector::contains<Dependency>(
+    return utils::ranges::contains(
         m_info.m_dependencies,
-        [id](Dependency t) -> bool { return t.m_id == id; }
+        [id](Dependency const& t) { return t.m_id == id; }
     );
 }
 
diff --git a/loader/src/load/Patch.cpp b/loader/src/load/Patch.cpp
index 30b652af..10dabf33 100644
--- a/loader/src/load/Patch.cpp
+++ b/loader/src/load/Patch.cpp
@@ -4,6 +4,7 @@
 #include <Geode/loader/Loader.hpp>
 #include <Geode/utils/casts.hpp>
 #include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <InternalLoader.hpp>
 
 #include <lilac/include/geode/core/hook/hook.hpp>
@@ -34,7 +35,7 @@ Result<Patch*> Mod::patch(void* address, byte_array data) {
 
 Result<> Mod::unpatch(Patch* patch) {
     if (patch->restore()) {
-        utils::vector::erase<Patch*>(m_patches, patch);
+        ranges::remove(m_patches, patch);
         delete patch;
         return Ok<>();
     }
diff --git a/loader/src/ui/internal/info/ModInfoLayer.cpp b/loader/src/ui/internal/info/ModInfoLayer.cpp
index 525207bb..2af43fa1 100644
--- a/loader/src/ui/internal/info/ModInfoLayer.cpp
+++ b/loader/src/ui/internal/info/ModInfoLayer.cpp
@@ -4,6 +4,7 @@
 #include "../list/ModListView.hpp"
 #include <Geode/utils/casts.hpp>
 #include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
 #include <Geode/ui/IconButtonSprite.hpp>
 #include <Geode/ui/MDPopup.hpp>
 #include "../settings/ModSettingsPopup.hpp"
@@ -520,7 +521,7 @@ void ModInfoLayer::onInstallMod(CCObject*) {
     createQuickPopup(
         "Install",
         "The following <cb>mods</c> will be installed: " +
-        utils::container::join(m_installation->toInstall(), ",") + ".",
+        ranges::join(m_installation->toInstall(), ",") + ".",
         "Cancel", "OK",
         [this](FLAlertLayer*, bool btn2) {
             if (btn2) {
diff --git a/loader/src/ui/nodes/MDTextArea.cpp b/loader/src/ui/nodes/MDTextArea.cpp
index 28c99d7b..809178c9 100644
--- a/loader/src/ui/nodes/MDTextArea.cpp
+++ b/loader/src/ui/nodes/MDTextArea.cpp
@@ -2,9 +2,13 @@
 #include <md4c.h>
 #include <Geode/binding/ProfilePage.hpp>
 #include <Geode/utils/cocos.hpp>
+#include <Geode/utils/convert.hpp>
 #include <Geode/utils/string.hpp>
 #include <Geode/utils/casts.hpp>
-#include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
+#include <Geode/utils/fetch.hpp>
+#include <Geode/utils/platform.hpp>
+#include <Geode/loader/Mod.hpp>
 
 USE_GEODE_NAMESPACE();
 
@@ -227,7 +231,7 @@ struct MDParser {
                     // rendering is done since the position of the 
                     // rendered labels may change after alignments 
                     // are adjusted
-                    utils::vector::push(s_codeSpans, rendered);
+                    ranges::push(s_codeSpans, rendered);
                 }
             } break;
 
diff --git a/loader/src/ui/nodes/Notification.cpp b/loader/src/ui/nodes/Notification.cpp
index a14a75b2..db84fd1b 100644
--- a/loader/src/ui/nodes/Notification.cpp
+++ b/loader/src/ui/nodes/Notification.cpp
@@ -2,7 +2,10 @@
 #include <Geode/ui/TextRenderer.hpp>
 #include <Geode/binding/GameSoundManager.hpp>
 #include <Geode/utils/cocos.hpp>
-#include <Geode/utils/vector.hpp>
+#include <Geode/utils/ranges.hpp>
+#include <Geode/utils/container.hpp>
+#include <Geode/utils/ranges.hpp>
+#include <Geode/loader/Mod.hpp>
 
 USE_GEODE_NAMESPACE();
 
@@ -439,7 +442,7 @@ Notification* NotificationBuilder::show() {
 bool NotificationManager::isInQueue(Notification* notification) {
     auto location = notification->m_location;
     if (m_notifications.count(location)) {
-        return utils::vector::contains(
+        return utils::ranges::contains(
             m_notifications.at(location), Ref(notification)
         );
     }
@@ -460,9 +463,7 @@ void NotificationManager::pop(Notification* notification) {
     auto location = notification->m_location;
     if (m_notifications.count(location)) {
         auto ref = Ref(notification);
-        utils::vector::erase(
-            m_notifications.at(location), ref
-        );
+        ranges::remove(m_notifications.at(location), ref);
         if (!m_notifications.at(location).size()) {
             m_notifications.erase(location);
         } else {