diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc
index 40a253759..9df975937 100644
--- a/common/src/app/common/files/changes.cljc
+++ b/common/src/app/common/files/changes.cljc
@@ -190,10 +190,9 @@
       [:type [:= :del-color]]
       [:id ::sm/uuid]]]
 
+    ;; DEPRECATED: remove before 2.3
     [:add-recent-color
-     [:map {:title "AddRecentColorChange"}
-      [:type [:= :add-recent-color]]
-      [:color ::ctc/recent-color]]]
+     [:map {:title "AddRecentColorChange"}]]
 
     [:add-media
      [:map {:title "AddMediaChange"}
@@ -656,18 +655,10 @@
   [data {:keys [id]}]
   (ctcl/delete-color data id))
 
+;; DEPRECATED: remove before 2.3
 (defmethod process-change :add-recent-color
-  [data {:keys [color]}]
-  ;; Moves the color to the top of the list and then truncates up to 15
-  (update
-   data
-   :recent-colors
-   (fn [rc]
-     (let [rc (->> rc (d/removev (partial ctc/eq-recent-color? color)))
-           rc (-> rc (conj color))]
-       (cond-> rc
-         (> (count rc) 15)
-         (subvec 1))))))
+  [data _]
+  data)
 
 ;; -- Media
 
diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc
index c3ecbd8a1..9c613a91d 100644
--- a/common/src/app/common/files/changes_builder.cljc
+++ b/common/src/app/common/files/changes_builder.cljc
@@ -607,13 +607,6 @@
     (reduce resize-parent changes all-parents)))
 
 ;; Library changes
-
-(defn add-recent-color
-  [changes color]
-  (-> changes
-      (update :redo-changes conj {:type :add-recent-color :color color})
-      (apply-changes-local)))
-
 (defn add-color
   [changes color]
   (-> changes
diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc
index c0c400a9a..78a7f8114 100644
--- a/common/src/app/common/types/color.cljc
+++ b/common/src/app/common/types/color.cljc
@@ -107,17 +107,16 @@
    [::sm/contains-any {:strict true} [:color :gradient :image]]])
 
 (sm/register! ::rgb-color type:rgb-color)
-
 (sm/register! ::color schema:color)
 (sm/register! ::gradient schema:gradient)
 (sm/register! ::image-color schema:image-color)
 (sm/register! ::recent-color schema:recent-color)
 
-(def check-color!
-  (sm/check-fn schema:color))
+(def valid-color?
+  (sm/lazy-validator schema:color))
 
-(def check-recent-color!
-  (sm/check-fn schema:recent-color))
+(def valid-recent-color?
+  (sm/lazy-validator schema:recent-color))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; HELPERS
@@ -392,13 +391,22 @@
 
     (process-shape-colors shape sync-color)))
 
-(defn eq-recent-color?
+(defn- eq-recent-color?
   [c1 c2]
   (or (= c1 c2)
       (and (some? (:color c1))
            (some? (:color c2))
            (= (:color c1) (:color c2)))))
 
+(defn add-recent-color
+  "Moves the color to the top of the list and then truncates up to 15"
+  [state file-id color]
+  (update state file-id (fn [colors]
+                          (let [colors (d/removev (partial eq-recent-color? color) colors)
+                                colors (conj colors color)]
+                            (cond-> colors
+                              (> (count colors) 15)
+                              (subvec 1))))))
 
 (defn stroke->color-att
   [stroke file-id shared-libs]
diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs
index dfb18f0d6..dd62ff70d 100644
--- a/frontend/src/app/main/data/workspace.cljs
+++ b/frontend/src/app/main/data/workspace.cljs
@@ -79,6 +79,7 @@
    [app.util.http :as http]
    [app.util.i18n :as i18n :refer [tr]]
    [app.util.router :as rt]
+   [app.util.storage :refer [storage]]
    [app.util.timers :as tm]
    [app.util.webapi :as wapi]
    [beicon.v2.core :as rx]
@@ -335,6 +336,7 @@
     ptk/UpdateEvent
     (update [_ state]
       (assoc state
+             :recent-colors (:recent-colors @storage)
              :workspace-ready? false
              :current-file-id file-id
              :current-project-id project-id
diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs
index 8e3589b50..a6c6cb8b3 100644
--- a/frontend/src/app/main/data/workspace/libraries.cljs
+++ b/frontend/src/app/main/data/workspace/libraries.cljs
@@ -48,6 +48,7 @@
    [app.util.color :as uc]
    [app.util.i18n :refer [tr]]
    [app.util.router :as rt]
+   [app.util.storage :as s]
    [app.util.time :as dt]
    [beicon.v2.core :as rx]
    [cuerdas.core :as str]
@@ -132,16 +133,21 @@
 
 (defn add-recent-color
   [color]
+
   (dm/assert!
    "expected valid recent color map"
-   (ctc/check-recent-color! color))
+   (ctc/valid-recent-color? color))
 
   (ptk/reify ::add-recent-color
-    ptk/WatchEvent
-    (watch [it _ _]
-      (let [changes (-> (pcb/empty-changes it)
-                        (pcb/add-recent-color color))]
-        (rx/of (dch/commit-changes changes))))))
+    ptk/UpdateEvent
+    (update [_ state]
+      (let [file-id (:current-file-id state)]
+        (update state :recent-colors ctc/add-recent-color file-id color)))
+
+    ptk/EffectEvent
+    (effect [_ state _]
+      (let [recent-colors (:recent-colors state)]
+        (swap! s/storage assoc :recent-colors recent-colors)))))
 
 (def clear-color-for-rename
   (ptk/reify ::clear-color-for-rename
@@ -168,8 +174,11 @@
 
   (dm/assert!
    "expected valid parameters"
-   (and (ctc/check-color! color)
-        (uuid? file-id)))
+   (ctc/valid-color? color))
+
+  (dm/assert!
+   "expected file-id"
+   (uuid? file-id))
 
   (ptk/reify ::update-color
     ptk/WatchEvent
diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs
index 36ec7a425..c0f32f643 100644
--- a/frontend/src/app/main/refs.cljs
+++ b/frontend/src/app/main/refs.cljs
@@ -236,9 +236,10 @@
              =))
 
 (def workspace-recent-colors
-  (l/derived (fn [data]
-               (get data :recent-colors []))
-             workspace-data))
+  (l/derived (fn [state]
+               (when-let [file-id (:current-file-id state)]
+                 (dm/get-in state [:recent-colors file-id])))
+             st/state))
 
 (def workspace-recent-fonts
   (l/derived (fn [data]