diff --git a/src/box/box.cc b/src/box/box.cc
index 6be2207c39c3d72d760603af269941c09c185ad9..34f85014c35a3eddf18b3b6a47203c09f014ef6e 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1224,10 +1224,7 @@ bootstrap_cluster(void)
 	/* Add a surrogate server id for snapshot rows */
 	vclock_add_server(&recovery->vclock, 0);
 
-	/* Process bootstrap.bin */
-	struct xstream bootstrap_stream;
-	xstream_create(&bootstrap_stream, apply_row);
-	recovery_bootstrap(recovery, &bootstrap_stream);
+	engine_bootstrap();
 
 	uint32_t server_id = 1;
 
diff --git a/src/box/engine.cc b/src/box/engine.cc
index 866e529c51974d33931d1f533114ab57240a0b48..6d68993ab1acd4e28a2bcb51a6ad54bd6125448c 100644
--- a/src/box/engine.cc
+++ b/src/box/engine.cc
@@ -268,6 +268,15 @@ engine_recover_to_checkpoint(int64_t checkpoint_id)
 	}
 }
 
+void
+engine_bootstrap()
+{
+	Engine *engine;
+	engine_foreach(engine) {
+		engine->bootstrap();
+	}
+}
+
 void
 engine_begin_join()
 {
diff --git a/src/box/engine.h b/src/box/engine.h
index 69b2f8b1bda9b636cb23134ec2ba56e68c582bfd..a54d0d99cd2524f8f153bb10920fa0a869362fee 100644
--- a/src/box/engine.h
+++ b/src/box/engine.h
@@ -134,6 +134,10 @@ class Engine {
 	 * binary log.
 	 */
 	virtual void endRecovery();
+	/**
+	 * Bootstrap an empty data directory
+	 */
+	virtual void bootstrap() {}
 	/**
 	 * Notify engine about a JOIN start (slave-side)
 	 */
@@ -240,6 +244,12 @@ engine_id(Handler *space)
 void
 engine_recover_to_checkpoint(int64_t checkpoint_id);
 
+/**
+ * Initialize an empty data directory
+ */
+void
+engine_bootstrap();
+
 /**
  * Called at the start of JOIN routine
  * on the replica.
diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc
index 16ae1df7f55898a113f996a67adb6ca5122ccaf9..009de80047f0cf6d69f3b0eaa0c14a2ace16b9af 100644
--- a/src/box/memtx_engine.cc
+++ b/src/box/memtx_engine.cc
@@ -44,6 +44,7 @@
 #include "iproto_constants.h"
 #include "xrow.h"
 #include "xstream.h"
+#include "bootstrap.h"
 #include "cluster.h"
 #include "relay.h"
 #include "schema.h"
@@ -997,6 +998,29 @@ MemtxEngine::commit(struct txn *txn, int64_t signature)
 	}
 }
 
+void
+MemtxEngine::bootstrap()
+{
+	/* Recover from bootstrap.snap */
+	say_info("initializing an empty data directory");
+	struct xdir dir;
+	xdir_create(&dir, "", SNAP, &uuid_nil);
+	FILE *f = fmemopen((void *) &bootstrap_bin,
+			   sizeof(bootstrap_bin), "r");
+	struct xlog *snap = xlog_open_stream_xc(&dir, 0, f, "bootstrap.snap");
+	struct xlog_cursor cursor;
+	xlog_cursor_open(&cursor, snap);
+	auto guard = make_scoped_guard([&]{
+		xlog_cursor_close(&cursor);
+		xlog_close(snap);
+		xdir_destroy(&dir);
+	});
+
+	struct xrow_header row;
+	while (xlog_cursor_next_xc(&cursor, &row) == 0)
+		recoverSnapshotRow(&row);
+}
+
 void
 MemtxEngine::beginJoin()
 {
diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h
index 6ca9201794a3dfb5c18eb883df02644af6a6c21f..b8a2a4386fc4e35d073354ad76645f25e6c9bd4d 100644
--- a/src/box/memtx_engine.h
+++ b/src/box/memtx_engine.h
@@ -59,6 +59,7 @@ struct MemtxEngine: public Engine {
 	virtual void rollback(struct txn *txn) override;
 	virtual void prepare(struct txn *txn) override;
 	virtual void commit(struct txn *txn, int64_t signature) override;
+	virtual void bootstrap() override;
 	virtual void beginJoin() override;
 	virtual void recoverToCheckpoint(int64_t lsn) override;
 	virtual void endRecovery() override;
diff --git a/src/box/recovery.cc b/src/box/recovery.cc
index f5faba506f29df466c77498da5f7cd663f18d4c0..2bf68c37648f7c9606f1c8f26d57a49a30e3a54d 100644
--- a/src/box/recovery.cc
+++ b/src/box/recovery.cc
@@ -32,7 +32,6 @@
 
 #include "scoped_guard.h"
 #include "fiber.h"
-#include "bootstrap.h"
 #include "xlog.h"
 #include "xrow.h"
 #include "xstream.h"
@@ -247,25 +246,6 @@ recover_xlog(struct recovery *r, struct xstream *stream, struct xlog *l,
 	}
 }
 
-void
-recovery_bootstrap(struct recovery *r, struct xstream *stream)
-{
-	/* Recover from bootstrap.snap */
-	say_info("initializing an empty data directory");
-	struct xdir dir;
-	xdir_create(&dir, "", SNAP, &uuid_nil);
-	const char *filename = "bootstrap.snap";
-	FILE *f = fmemopen((void *) &bootstrap_bin,
-			   sizeof(bootstrap_bin), "r");
-	struct xlog *snap = xlog_open_stream_xc(&dir, 0, f, filename);
-	auto guard = make_scoped_guard([&]{
-		xlog_close(snap);
-		xdir_destroy(&dir);
-	});
-	/** The snapshot must have a EOF marker. */
-	recover_xlog(r, stream, snap, NULL);
-}
-
 /**
  * Find out if there are new .xlog files since the current
  * LSN, and read them all up.
diff --git a/src/box/recovery.h b/src/box/recovery.h
index 61a7b3c598efd9233d9c39129bc4a515d084f339..7efda2a35c0f8efde85bc3b130a0c0291451e63f 100644
--- a/src/box/recovery.h
+++ b/src/box/recovery.h
@@ -72,9 +72,6 @@ recovery_delete(struct recovery *r);
 void
 recovery_exit(struct recovery *r);
 
-void
-recovery_bootstrap(struct recovery *r, struct xstream *stream);
-
 void
 recovery_follow_local(struct recovery *r, struct xstream *stream,
 		      const char *name, ev_tstamp wal_dir_rescan_delay);