diff --git a/src/binstall/install.rs b/src/binstall/install.rs
index c1b78fc3..875344af 100644
--- a/src/binstall/install.rs
+++ b/src/binstall/install.rs
@@ -108,29 +108,21 @@ async fn install_from_package(
 
         let bins: BTreeSet<String> = bin_files.into_iter().map(|bin| bin.base_name).collect();
 
-        {
-            debug!("Writing .crates.toml");
-            let mut c1 = metafiles::v1::CratesToml::load().unwrap_or_default();
-            c1.insert(cvs.clone(), bins.clone());
-            c1.write()?;
-        }
+        debug!("Writing .crates.toml");
+        metafiles::v1::CratesToml::append(&cvs, bins.clone())?;
 
-        {
-            debug!("Writing .crates2.json");
-            let mut c2 = metafiles::v2::Crates2Json::load().unwrap_or_default();
-            c2.insert(
-                cvs,
-                metafiles::v2::CrateInfo {
-                    version_req: Some(version),
-                    bins,
-                    profile: "release".into(),
-                    target: fetcher.target().to_string(),
-                    rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
-                    ..Default::default()
-                },
-            );
-            c2.write()?;
-        }
+        debug!("Writing .crates2.json");
+        metafiles::v2::Crates2Json::append(
+            &cvs,
+            metafiles::v2::CrateInfo {
+                version_req: Some(version),
+                bins,
+                profile: "release".into(),
+                target: fetcher.target().to_string(),
+                rustc: format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
+                ..Default::default()
+            },
+        )?;
 
         Ok(())
     })
diff --git a/src/metafiles/cvs.rs b/src/metafiles/cvs.rs
index 2b8f2214..b56ab5fc 100644
--- a/src/metafiles/cvs.rs
+++ b/src/metafiles/cvs.rs
@@ -1,4 +1,4 @@
-use std::{fmt, str::FromStr};
+use std::{borrow::Cow, fmt, str::FromStr};
 
 use miette::Diagnostic;
 use once_cell::sync::Lazy;
@@ -116,6 +116,7 @@ impl<'de> Deserialize<'de> for CrateVersionSource {
     where
         D: Deserializer<'de>,
     {
-        Self::from_str(&String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
+        let s = Cow::<'_, str>::deserialize(deserializer)?;
+        Self::from_str(&s).map_err(serde::de::Error::custom)
     }
 }
diff --git a/src/metafiles/v1.rs b/src/metafiles/v1.rs
index 19f0ab8f..3b98568d 100644
--- a/src/metafiles/v1.rs
+++ b/src/metafiles/v1.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::{BTreeMap, BTreeSet},
-    fs,
+    fs, io,
     path::{Path, PathBuf},
     str::FromStr,
 };
@@ -14,7 +14,7 @@ use crate::cargo_home;
 
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 pub struct CratesToml {
-    v1: BTreeMap<CrateVersionSource, BTreeSet<String>>,
+    v1: BTreeMap<String, BTreeSet<String>>,
 }
 
 impl CratesToml {
@@ -31,8 +31,8 @@ impl CratesToml {
         Self::from_str(&file)
     }
 
-    pub fn insert(&mut self, cvs: CrateVersionSource, bins: BTreeSet<String>) {
-        self.v1.insert(cvs, bins);
+    pub fn insert(&mut self, cvs: &CrateVersionSource, bins: BTreeSet<String>) {
+        self.v1.insert(cvs.to_string(), bins);
     }
 
     pub fn write(&self) -> Result<(), CratesTomlParseError> {
@@ -43,6 +43,31 @@ impl CratesToml {
         fs::write(path, &toml::to_vec(&self)?)?;
         Ok(())
     }
+
+    pub fn append_to_path(
+        path: impl AsRef<Path>,
+        cvs: &CrateVersionSource,
+        bins: BTreeSet<String>,
+    ) -> Result<(), CratesTomlParseError> {
+        let mut c1 = match Self::load_from_path(path.as_ref()) {
+            Ok(c1) => c1,
+            Err(CratesTomlParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
+                Self::default()
+            }
+            Err(err) => return Err(err),
+        };
+        c1.insert(cvs, bins);
+        c1.write_to_path(path.as_ref())?;
+
+        Ok(())
+    }
+
+    pub fn append(
+        cvs: &CrateVersionSource,
+        bins: BTreeSet<String>,
+    ) -> Result<(), CratesTomlParseError> {
+        Self::append_to_path(Self::default_path()?, cvs, bins)
+    }
 }
 
 impl FromStr for CratesToml {
@@ -55,7 +80,7 @@ impl FromStr for CratesToml {
 #[derive(Debug, Diagnostic, Error)]
 pub enum CratesTomlParseError {
     #[error(transparent)]
-    Io(#[from] std::io::Error),
+    Io(#[from] io::Error),
 
     #[error(transparent)]
     TomlParse(#[from] toml::de::Error),
diff --git a/src/metafiles/v2.rs b/src/metafiles/v2.rs
index 4724b1e8..f9ea6a68 100644
--- a/src/metafiles/v2.rs
+++ b/src/metafiles/v2.rs
@@ -1,6 +1,6 @@
 use std::{
     collections::{BTreeMap, BTreeSet},
-    fs,
+    fs, io,
     path::{Path, PathBuf},
 };
 
@@ -13,7 +13,7 @@ use crate::cargo_home;
 
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
 pub struct Crates2Json {
-    pub installs: BTreeMap<CrateVersionSource, CrateInfo>,
+    pub installs: BTreeMap<String, CrateInfo>,
 }
 
 #[derive(Clone, Debug, Default, Deserialize, Serialize)]
@@ -48,12 +48,12 @@ impl Crates2Json {
     }
 
     pub fn load_from_path(path: impl AsRef<Path>) -> Result<Self, Crates2JsonParseError> {
-        let file = fs::read_to_string(path)?;
-        Ok(serde_json::from_str(&file)?)
+        let file = fs::File::open(path.as_ref())?;
+        Ok(serde_json::from_reader(file)?)
     }
 
-    pub fn insert(&mut self, cvs: CrateVersionSource, info: CrateInfo) {
-        self.installs.insert(cvs, info);
+    pub fn insert(&mut self, cvs: &CrateVersionSource, info: CrateInfo) {
+        self.installs.insert(cvs.to_string(), info);
     }
 
     pub fn write(&self) -> Result<(), Crates2JsonParseError> {
@@ -61,15 +61,38 @@ impl Crates2Json {
     }
 
     pub fn write_to_path(&self, path: impl AsRef<Path>) -> Result<(), Crates2JsonParseError> {
-        fs::write(path, &serde_json::to_vec(&self)?)?;
+        let file = fs::File::create(path.as_ref())?;
+        serde_json::to_writer(file, &self)?;
         Ok(())
     }
+
+    pub fn append_to_path(
+        path: impl AsRef<Path>,
+        cvs: &CrateVersionSource,
+        info: CrateInfo,
+    ) -> Result<(), Crates2JsonParseError> {
+        let mut c2 = match Self::load_from_path(path.as_ref()) {
+            Ok(c2) => c2,
+            Err(Crates2JsonParseError::Io(io_err)) if io_err.kind() == io::ErrorKind::NotFound => {
+                Self::default()
+            }
+            Err(err) => return Err(err),
+        };
+        c2.insert(cvs, info);
+        c2.write_to_path(path.as_ref())?;
+
+        Ok(())
+    }
+
+    pub fn append(cvs: &CrateVersionSource, info: CrateInfo) -> Result<(), Crates2JsonParseError> {
+        Self::append_to_path(Self::default_path()?, cvs, info)
+    }
 }
 
 #[derive(Debug, Diagnostic, Error)]
 pub enum Crates2JsonParseError {
     #[error(transparent)]
-    Io(#[from] std::io::Error),
+    Io(#[from] io::Error),
 
     #[error(transparent)]
     Json(#[from] serde_json::Error),