diff --git a/lektor_nkdb/src/database/epoch.rs b/lektor_nkdb/src/database/epoch.rs
index c09db611feea06b8f69d05d273a3cc88ea580b34..36c63d2b3f4e7216ca02da0509d0cd341e0b9237 100644
--- a/lektor_nkdb/src/database/epoch.rs
+++ b/lektor_nkdb/src/database/epoch.rs
@@ -45,6 +45,11 @@ impl Epoch {
         self.0.get(&id)
     }
 
+    /// Returns whever the [Epoch] contains the [KId] or not.
+    pub fn contains(&self, id: &KId) -> bool {
+        self.0.contains_key(id)
+    }
+
     /// Get access to the karas in the epoch.
     pub fn data(&self) -> &EpochData {
         &self.0
diff --git a/lektor_nkdb/src/database/pool.rs b/lektor_nkdb/src/database/pool.rs
index ac76b200b3d8182bb57d92e94b74d6153bc9a060..e3a975da6df42d8a9b9870659a8e76f9fbdcfa3c 100644
--- a/lektor_nkdb/src/database/pool.rs
+++ b/lektor_nkdb/src/database/pool.rs
@@ -28,16 +28,27 @@ impl Pool {
         // Compress things if needed!
         let this = Self::default();
         let vec = futures::future::join_all(iter.into_iter().map(|(kid, rkid)| async {
-            (
-                this.get_str::<KId>(kid.0).await,
-                this.get_str::<RemoteKId>(rkid.0).await,
-            )
+            let kid = this.get_str::<KId>(kid.0).await;
+            let rkid = this.get_str::<RemoteKId>(rkid.0).await;
+            (kid, rkid)
         }))
         .await;
         let _ = std::mem::replace(&mut (*this.id_mapping.write().await), vec);
         this
     }
 
+    /// Get other possible ids from an id, we may want to do that to get all the local ids for a
+    /// remote id, to get a more up-to-date version of a kara.
+    pub(crate) async fn get_other_locals(&self, id: KId) -> Vec<KId> {
+        let mapping = self.id_mapping.read().await;
+
+        let find_remote = |(kid, rkid): &_| id.eq(kid).then_some(rkid).cloned();
+        let remote = mapping.iter().find_map(find_remote).expect("no remote id");
+
+        let find_locals = |(kid, rkid): &(KId, _)| remote.eq(rkid).then_some(kid.clone());
+        mapping.iter().filter_map(find_locals).collect()
+    }
+
     /// Get the tuple (local, remote) from the string representation of the remote id. Id the local
     /// id is not present, returns none, else some(local_id).
     pub(crate) async fn get_from_remote(&self, rkid: impl AsRef<str>) -> (Option<KId>, RemoteKId) {
@@ -77,6 +88,14 @@ impl Pool {
             .into()
     }
 
+    /// Same as [Pool::get_str], but don't create the id if not present to avoid being DOSed...
+    pub(crate) async fn try_get_str<I: sealed::Id>(&self, id: impl AsRef<str>) -> Option<I> {
+        let mut hash = DefaultHasher::new();
+        hash.write(id.as_ref().as_bytes());
+        let this = self.string_cache.write().await;
+        this.get(&hash.finish()).cloned().map(Into::into)
+    }
+
     /// Get the maximal id present in the pool.
     pub(crate) async fn maximal_id(&self) -> u64 {
         let list = self.id_mapping.read().await;
diff --git a/lektor_nkdb/src/lib.rs b/lektor_nkdb/src/lib.rs
index e5690d8e71d96db53d3f4df8a4bb15fc98f51dd7..f501a0028196217e114fe6976c72ebb19ab58438 100644
--- a/lektor_nkdb/src/lib.rs
+++ b/lektor_nkdb/src/lib.rs
@@ -113,11 +113,34 @@ impl<Storage: DatabaseStorage> Database<Storage> {
         .await
     }
 
+    /// Refresh the [KId]s of the playlists to use a most up-to-date version of a kara if
+    /// available. Should be called after a successfull update process. In case of failure we log
+    /// the error and do nothing else...
+    pub async fn refresh_playlist_contents(&self) {
+        let Some(epoch) = self.last_epoch().await else {
+            log::error!("no epoch in database, can't refresh playlists");
+            return;
+        };
+        for name in self.playlists.list_names().await {
+            log::info!("refresh ids for playlist {name}");
+            let ids = stream::iter(self.playlists.get_content(&name).await.unwrap_or_default())
+                .then(|id| async {
+                    let locals = self.pool.get_other_locals(id).await;
+                    locals.into_iter().filter(|id| epoch.contains(id))
+                })
+                .collect::<FuturesUnordered<_>>();
+            self.playlists
+                .refresh(&name, ids.await.into_iter().flatten().collect::<Vec<KId>>())
+                .await
+                .map_err(|err| log::error!("failed to refresh ids of playlist {name}: {err}"))
+                .unwrap_or_default();
+        }
+    }
+
     /// Get the [KId] out of its string representation. We query the pool to guaranty the pointer
     /// unicity for faster checks.
-    pub async fn get_kid_from_str(&self, kid: impl AsRef<str>) -> KId {
-        log::error!("find a way to get the str only if it exists...");
-        self.pool.get_str(kid).await
+    pub async fn get_kid_from_str(&self, kid: impl AsRef<str>) -> Option<KId> {
+        self.pool.try_get_str(kid).await
     }
 
     /// Get a [Kara] by its [u64] representation in the last epoch.
diff --git a/lektor_nkdb/src/playlist/register.rs b/lektor_nkdb/src/playlist/register.rs
index 68b31b4761b2e2fa07b4c8e4b98c70941c03500a..a85aaaf8de2ebad81e79ace87dcc549d55eea699 100644
--- a/lektor_nkdb/src/playlist/register.rs
+++ b/lektor_nkdb/src/playlist/register.rs
@@ -2,7 +2,7 @@
 //! change.
 
 use crate::{DatabaseStorage, KId, Playlist, PlaylistInfo, PlaylistName};
-use anyhow::{bail, Result};
+use anyhow::{anyhow, bail, Result};
 use hashbrown::{hash_map::OccupiedEntry, HashMap};
 use lektor_utils::log;
 use rand::{seq::SliceRandom, thread_rng};
@@ -176,6 +176,25 @@ impl_playlists! {
         self.0.iter().map(|(name, plt)| (name.clone(), plt.deref().clone())).collect()
     }
 
+    /// Get the list of all the playlists.
+    read fn list_names(&self) -> Vec<PlaylistName> {
+        self.0.iter().map(|(name, _)| name.clone()).collect()
+    }
+
+    /// Refresh some ids of a playlist with the new ones. Here we skip the user check thing as this
+    /// function should not be called by a user but as part of the update process.
+    write fn refresh(&self, name: impl AsRef<str>, ids: Vec<KId>) -> Result<()> {
+        let (mut ids, name) = (ids, name.as_ref());
+        let plt = self.0.get_mut(name).ok_or_else(|| anyhow!("no playlist {name} to refresh"))?;
+        ids.retain(|id| !plt.content.contains(id));
+        if ids.is_empty() {
+            log::warn!("no ids to refresh the playlist {name} with...");
+        } else {
+            plt.content.append(&mut ids);
+        }
+        Ok(())
+    }
+
     /// Rename a playlist.
     write fn rename(&self, name: PlaylistName, new_name: PlaylistName, user: impl AsRef<str>, admin: bool) -> Result<()> {
         if self.0.contains_key(&new_name) {
diff --git a/lektord/src/app/routes.rs b/lektord/src/app/routes.rs
index fca68aefac73fc7db22f9a0a5a627d0728efe29d..e95260b2866bbf9d41a04760445817f178c1204d 100644
--- a/lektord/src/app/routes.rs
+++ b/lektord/src/app/routes.rs
@@ -116,8 +116,10 @@ pub(crate) async fn get_kara_by_kid(
     Path(id): Path<String>,
 ) -> Result<Json<Kara>, LektordError> {
     log::error!("find a way to not clone the kara");
-    let id = state.database.get_kid_from_str(&decode_base64(id)?).await;
-    Ok(Json(state.database.get_kara_by_kid(id).await?.clone()))
+    match state.database.get_kid_from_str(&decode_base64(&id)?).await {
+        Some(id) => Ok(Json(state.database.get_kara_by_kid(id).await?.clone())),
+        None => Err(anyhow!("no kara found with id {id}").into()),
+    }
 }
 
 /// Search some karas from a search set with a regex. We take the json argument as base64 encoded
@@ -263,17 +265,15 @@ pub(crate) async fn adm_update(
             .expect("failed to build tokio runtime to update database from repo");
         let local = LocalSet::new();
         local.spawn_local(async move {
-            match tokio::task::spawn_local(async move {
+            let res = tokio::task::spawn_local(async move {
                 let handle = state.database.update().await;
                 let count = state.repo.update_with(&handle).await?;
                 handle.finished().await;
+                state.database.refresh_playlist_contents().await;
                 Ok::<_, LektordError>(count)
-            })
-            .await
-            {
-                Ok(Ok(count)) => {
-                    log::info!("finished updating database, toto downloaded karas: {count}")
-                }
+            });
+            match res.await {
+                Ok(Ok(count)) => log::info!("finished updating database with karas: {count}"),
                 Ok(Err(err)) => log::error!("{err}"),
                 Err(err) => log::error!("{err}"),
             }