diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs
index 350f34aa..4db98a04 100644
--- a/helix-term/tests/test/commands/write.rs
+++ b/helix-term/tests/test/commands/write.rs
@@ -604,6 +604,51 @@ async fn test_symlink_write_fail() -> anyhow::Result<()> {
     Ok(())
 }
 
+#[tokio::test(flavor = "multi_thread")]
+async fn test_symlink_write_relative() -> anyhow::Result<()> {
+    #[cfg(unix)]
+    use std::os::unix::fs::symlink;
+    #[cfg(not(unix))]
+    use std::os::windows::fs::symlink_file as symlink;
+
+    // tempdir
+    // |- - b
+    // |  |- file
+    // |- linked (symlink to file)
+    let dir = tempfile::tempdir()?;
+    let inner_dir = dir.path().join("b");
+    std::fs::create_dir(&inner_dir)?;
+
+    let mut file = tempfile::NamedTempFile::new_in(&inner_dir)?;
+    let symlink_path = dir.path().join("linked");
+    let relative_path = std::path::PathBuf::from("b").join(file.path().file_name().unwrap());
+    symlink(relative_path, &symlink_path)?;
+
+    let mut app = helpers::AppBuilder::new()
+        .with_file(&symlink_path, None)
+        .build()?;
+
+    test_key_sequence(
+        &mut app,
+        Some("ithe gostak distims the doshes<ret><esc>:w<ret>"),
+        None,
+        false,
+    )
+    .await?;
+
+    reload_file(&mut file).unwrap();
+    let mut file_content = String::new();
+    file.as_file_mut().read_to_string(&mut file_content)?;
+
+    assert_eq!(
+        LineFeedHandling::Native.apply("the gostak distims the doshes"),
+        file_content
+    );
+    assert!(symlink_path.is_symlink());
+
+    Ok(())
+}
+
 async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> {
     let mut file = tempfile::NamedTempFile::new()?;
 
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index b8d318bb..23b597a3 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -895,7 +895,15 @@ impl Document {
             }
             let write_path = tokio::fs::read_link(&path)
                 .await
-                .unwrap_or_else(|_| path.clone());
+                .ok()
+                .and_then(|p| {
+                    if p.is_relative() {
+                        path.parent().map(|parent| parent.join(p))
+                    } else {
+                        Some(p)
+                    }
+                })
+                .unwrap_or_else(|| path.clone());
 
             if readonly(&write_path) {
                 bail!(std::io::Error::new(