diff --git a/book/src/editor.md b/book/src/editor.md
index 88541a7b..ba03e90e 100644
--- a/book/src/editor.md
+++ b/book/src/editor.md
@@ -32,7 +32,6 @@
 | `gutters` | Gutters to display: Available are `diagnostics` and `diff` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` |
 | `auto-completion` | Enable automatic pop up of auto-completion | `true` |
 | `auto-format` | Enable automatic formatting on save | `true` |
-| `auto-save` | Enable automatic saving on the focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal | `false` |
 | `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. | `250` |
 | `completion-timeout` | Time in milliseconds after typing a word character before completions are shown, set to 5 for instant.  | `250` |
 | `preview-completion-insert` | Whether to apply completion item instantly when selected | `true` |
@@ -222,6 +221,16 @@ name = "rust"
 '<' = '>'
 ```
 
+### `[editor.auto-save]` Section
+
+Control auto save behavior.
+
+| Key | Description | Default |
+|--|--|---------|
+| `focus-lost` | Enable automatic saving on the focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal | `false` |
+| `after-delay.enable` | Enable automatic saving after `auto-save.after-delay.timeout` milliseconds have passed since last edit. | `false` |
+| `after-delay.timeout` | Time in milliseconds since last edit before auto save timer triggers. | `3000` |
+
 ### `[editor.search]` Section
 
 Search specific options.
diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs
index d45809d3..fc927313 100644
--- a/helix-term/src/handlers.rs
+++ b/helix-term/src/handlers.rs
@@ -5,12 +5,14 @@ use helix_event::AsyncHook;
 
 use crate::config::Config;
 use crate::events;
+use crate::handlers::auto_save::AutoSaveHandler;
 use crate::handlers::completion::CompletionHandler;
 use crate::handlers::signature_help::SignatureHelpHandler;
 
 pub use completion::trigger_auto_completion;
 pub use helix_view::handlers::Handlers;
 
+mod auto_save;
 pub mod completion;
 mod signature_help;
 
@@ -19,11 +21,16 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers {
 
     let completions = CompletionHandler::new(config).spawn();
     let signature_hints = SignatureHelpHandler::new().spawn();
+    let auto_save = AutoSaveHandler::new().spawn();
+
     let handlers = Handlers {
         completions,
         signature_hints,
+        auto_save,
     };
+
     completion::register_hooks(&handlers);
     signature_help::register_hooks(&handlers);
+    auto_save::register_hooks(&handlers);
     handlers
 }
diff --git a/helix-term/src/handlers/auto_save.rs b/helix-term/src/handlers/auto_save.rs
new file mode 100644
index 00000000..d3f7f6fc
--- /dev/null
+++ b/helix-term/src/handlers/auto_save.rs
@@ -0,0 +1,61 @@
+use std::time::Duration;
+
+use anyhow::Ok;
+use arc_swap::access::Access;
+
+use helix_event::{register_hook, send_blocking};
+use helix_view::{events::DocumentDidChange, handlers::Handlers, Editor};
+use tokio::time::Instant;
+
+use crate::{
+    commands, compositor,
+    job::{self, Jobs},
+};
+
+#[derive(Debug)]
+pub(super) struct AutoSaveHandler;
+
+impl AutoSaveHandler {
+    pub fn new() -> AutoSaveHandler {
+        AutoSaveHandler
+    }
+}
+
+impl helix_event::AsyncHook for AutoSaveHandler {
+    type Event = u64;
+
+    fn handle_event(
+        &mut self,
+        timeout: Self::Event,
+        _: Option<tokio::time::Instant>,
+    ) -> Option<Instant> {
+        Some(Instant::now() + Duration::from_millis(timeout))
+    }
+
+    fn finish_debounce(&mut self) {
+        job::dispatch_blocking(move |editor, _| request_auto_save(editor))
+    }
+}
+
+fn request_auto_save(editor: &mut Editor) {
+    let context = &mut compositor::Context {
+        editor,
+        scroll: Some(0),
+        jobs: &mut Jobs::new(),
+    };
+
+    if let Err(e) = commands::typed::write_all_impl(context, false, false) {
+        context.editor.set_error(format!("{}", e));
+    }
+}
+
+pub(super) fn register_hooks(handlers: &Handlers) {
+    let tx = handlers.auto_save.clone();
+    register_hook!(move |event: &mut DocumentDidChange<'_>| {
+        let config = event.doc.config.load();
+        if config.auto_save.after_delay.enable {
+            send_blocking(&tx, config.auto_save.after_delay.timeout);
+        }
+        Ok(())
+    });
+}
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 97f90f62..d584afbb 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -1451,7 +1451,7 @@ impl Component for EditorView {
                 EventResult::Consumed(None)
             }
             Event::FocusLost => {
-                if context.editor.config().auto_save {
+                if context.editor.config().auto_save.focus_lost {
                     if let Err(e) = commands::typed::write_all_impl(context, false, false) {
                         context.editor.set_error(format!("{}", e));
                     }
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index ef491853..635f7261 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -55,6 +55,8 @@ use arc_swap::{
     ArcSwap,
 };
 
+pub const DEFAULT_AUTO_SAVE_DELAY: u64 = 3000;
+
 fn deserialize_duration_millis<'de, D>(deserializer: D) -> Result<Duration, D::Error>
 where
     D: serde::Deserializer<'de>,
@@ -266,8 +268,11 @@ pub struct Config {
     pub auto_completion: bool,
     /// Automatic formatting on save. Defaults to true.
     pub auto_format: bool,
-    /// Automatic save on focus lost. Defaults to false.
-    pub auto_save: bool,
+    /// Automatic save on focus lost and/or after delay.
+    /// Time delay in milliseconds since last edit after which auto save timer triggers.
+    /// Time delay defaults to false with 3000ms delay. Focus lost defaults to false.
+    #[serde(deserialize_with = "deserialize_auto_save")]
+    pub auto_save: AutoSave,
     /// Set a global text_width
     pub text_width: usize,
     /// Time in milliseconds since last keypress before idle timers trigger.
@@ -771,6 +776,61 @@ impl WhitespaceRender {
     }
 }
 
+#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct AutoSave {
+    /// Auto save after a delay in milliseconds. Defaults to disabled.
+    #[serde(default)]
+    pub after_delay: AutoSaveAfterDelay,
+    /// Auto save on focus lost. Defaults to false.
+    #[serde(default)]
+    pub focus_lost: bool,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct AutoSaveAfterDelay {
+    #[serde(default)]
+    /// Enable auto save after delay. Defaults to false.
+    pub enable: bool,
+    #[serde(default = "default_auto_save_delay")]
+    /// Time delay in milliseconds. Defaults to [DEFAULT_AUTO_SAVE_DELAY].
+    pub timeout: u64,
+}
+
+impl Default for AutoSaveAfterDelay {
+    fn default() -> Self {
+        Self {
+            enable: false,
+            timeout: DEFAULT_AUTO_SAVE_DELAY,
+        }
+    }
+}
+
+fn default_auto_save_delay() -> u64 {
+    DEFAULT_AUTO_SAVE_DELAY
+}
+
+fn deserialize_auto_save<'de, D>(deserializer: D) -> Result<AutoSave, D::Error>
+where
+    D: serde::Deserializer<'de>,
+{
+    #[derive(Deserialize, Serialize)]
+    #[serde(untagged, deny_unknown_fields, rename_all = "kebab-case")]
+    enum AutoSaveToml {
+        EnableFocusLost(bool),
+        AutoSave(AutoSave),
+    }
+
+    match AutoSaveToml::deserialize(deserializer)? {
+        AutoSaveToml::EnableFocusLost(focus_lost) => Ok(AutoSave {
+            focus_lost,
+            ..Default::default()
+        }),
+        AutoSaveToml::AutoSave(auto_save) => Ok(auto_save),
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 #[serde(default)]
 pub struct WhitespaceCharacters {
@@ -881,7 +941,7 @@ impl Default for Config {
             auto_pairs: AutoPairConfig::default(),
             auto_completion: true,
             auto_format: true,
-            auto_save: false,
+            auto_save: AutoSave::default(),
             idle_timeout: Duration::from_millis(250),
             completion_timeout: Duration::from_millis(250),
             preview_completion_insert: true,
diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs
index 724e7b19..352abb88 100644
--- a/helix-view/src/handlers.rs
+++ b/helix-view/src/handlers.rs
@@ -11,6 +11,7 @@ pub struct Handlers {
     // only public because most of the actual implementation is in helix-term right now :/
     pub completions: Sender<lsp::CompletionEvent>,
     pub signature_hints: Sender<lsp::SignatureHelpEvent>,
+    pub auto_save: Sender<u64>,
 }
 
 impl Handlers {