diff --git a/components/st3m/st3m_tar.c b/components/st3m/st3m_tar.c
index 461ba66825c94b9cd883aa843fb7bd8e61316631..465d6adfeda09c49dbcf34c6d9144ee2bd03f118 100644
--- a/components/st3m/st3m_tar.c
+++ b/components/st3m/st3m_tar.c
@@ -7,6 +7,8 @@
 #include "esp_log.h"
 #include "miniz.h"
 
+#define READ_BUF_SIZE 4096
+
 static const char *TAG = "st3m-tar";
 
 void st3m_tar_parser_init(st3m_tar_parser_t *parser) {
@@ -201,9 +203,14 @@ static int _mkpath(char *file_path, mode_t mode) {
 static void _extractor_on_file_start(void *user, const char *name, size_t size,
                                      char type) {
     st3m_tar_extractor_t *extractor = (st3m_tar_extractor_t *)user;
-    if (extractor->cur_file != NULL) {
-        fclose(extractor->cur_file);
-        extractor->cur_file = NULL;
+    if (extractor->cur_file_contents != NULL) {
+        free(extractor->cur_file_contents);
+        extractor->cur_file_contents = NULL;
+        extractor->cur_file_offset = NULL;
+    }
+    if (extractor->cur_file_path != NULL) {
+        free(extractor->cur_file_path);
+        extractor->cur_file_path = NULL;
     }
 
     if (size == 0 || type != '0') {
@@ -222,33 +229,88 @@ static void _extractor_on_file_start(void *user, const char *name, size_t size,
         ESP_LOGW(TAG, "Failed to create parent directory for %s: %s", path,
                  strerror(errno));
     }
-    extractor->cur_file = fopen(path, "w");
-    if (extractor->cur_file == NULL) {
-        ESP_LOGW(TAG, "Failed to create %s: %s", path, strerror(errno));
-    }
+
+    extractor->cur_file_path = path;
+
+    extractor->cur_file_contents = malloc(size);
+    extractor->cur_file_offset = extractor->cur_file_contents;
+    extractor->cur_file_size = size;
 
     if (extractor->on_file != NULL) {
         extractor->on_file(path);
     }
-    free(path);
 }
 
 static void _extractor_on_file_data(void *user, const uint8_t *buffer,
                                     size_t bufsize) {
     st3m_tar_extractor_t *extractor = (st3m_tar_extractor_t *)user;
-    if (extractor->cur_file == NULL) {
+    if (extractor->cur_file_contents == NULL) {
         return;
     }
-    fwrite(buffer, 1, bufsize, extractor->cur_file);
+
+    memcpy(extractor->cur_file_offset, buffer, bufsize);
+    extractor->cur_file_offset += bufsize;
+}
+
+static bool _is_write_needed(char *path, uint8_t *contents, size_t size) {
+    struct stat sb;
+    if (stat(path, &sb) != 0 || sb.st_size != size) {
+        // file doesn't exist or size changed
+        return true;
+    }
+
+    // go on to compare file contents
+    FILE *file = fopen(path, "r");
+    if (file == NULL) {
+        return true;
+    }
+
+    // malloc because we don't have that much stack
+    uint8_t *buf = malloc(READ_BUF_SIZE);
+
+    for (size_t off = 0; off < size; off += READ_BUF_SIZE) {
+        size_t leftover = (size - off);
+        size_t read_size =
+            (leftover < READ_BUF_SIZE) ? leftover : READ_BUF_SIZE;
+
+        if ((fread(buf, 1, read_size, file) != read_size) ||
+            (memcmp(buf, contents + off, read_size) != 0)) {
+            fclose(file);
+            free(buf);
+            return true;
+        }
+    }
+
+    fclose(file);
+    free(buf);
+    return false;
 }
 
 static void _extractor_on_file_end(void *user) {
     st3m_tar_extractor_t *extractor = (st3m_tar_extractor_t *)user;
-    if (extractor->cur_file == NULL) {
+    if (extractor->cur_file_contents == NULL) {
         return;
     }
-    fclose(extractor->cur_file);
-    extractor->cur_file = NULL;
+
+    if (_is_write_needed(extractor->cur_file_path, extractor->cur_file_contents,
+                         extractor->cur_file_size)) {
+        FILE *cur_file = fopen(extractor->cur_file_path, "w");
+        if (cur_file == NULL) {
+            ESP_LOGW(TAG, "Failed to create %s: %s", extractor->cur_file_path,
+                     strerror(errno));
+        } else {
+            fwrite(extractor->cur_file_contents, 1, extractor->cur_file_size,
+                   cur_file);
+            fflush(cur_file);
+            fclose(cur_file);
+        }
+    }
+
+    free(extractor->cur_file_contents);
+    free(extractor->cur_file_path);
+    extractor->cur_file_contents = NULL;
+    extractor->cur_file_offset = NULL;
+    extractor->cur_file_path = NULL;
 }
 
 void st3m_tar_extractor_init(st3m_tar_extractor_t *extractor) {
diff --git a/components/st3m/st3m_tar.h b/components/st3m/st3m_tar.h
index a0fb4f87f84eee0c10a9b08dbe94af05254b511e..e3383132112375f56b1d989c5ba28c8ccce180d6 100644
--- a/components/st3m/st3m_tar.h
+++ b/components/st3m/st3m_tar.h
@@ -51,7 +51,11 @@ typedef struct {
     // If set, will be called any file begins extraction. Useful for feedback.
     void (*on_file)(const char *name);
 
-    FILE *cur_file;
+    char *cur_file_path;
+    uint8_t *cur_file_contents;
+    uint8_t *cur_file_offset;
+    size_t cur_file_size;
+
     st3m_tar_parser_t parser;
 } st3m_tar_extractor_t;