diff --git a/config/config.exs b/config/config.exs
index 2e6b0796a..1f10167e5 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -551,6 +551,7 @@
   queues: [
     activity_expiration: 10,
     token_expiration: 5,
+    backup: 1,
     federator_incoming: 50,
     federator_outgoing: 50,
     ingestion_queue: 50,
diff --git a/config/description.exs b/config/description.exs
index 6fa78a5d1..13e44afe8 100644
--- a/config/description.exs
+++ b/config/description.exs
@@ -2288,6 +2288,12 @@
             description: "Activity expiration queue",
             suggestions: [10]
           },
+          %{
+            key: :backup,
+            type: :integer,
+            description: "Backup queue",
+            suggestions: [1]
+          },
           %{
             key: :attachments_cleanup,
             type: :integer,
diff --git a/lib/pleroma/backup.ex b/lib/pleroma/backup.ex
index 4580d8f92..9b5d2625f 100644
--- a/lib/pleroma/backup.ex
+++ b/lib/pleroma/backup.ex
@@ -30,7 +30,7 @@ defmodule Pleroma.Backup do
   def create(user) do
     with :ok <- validate_limit(user),
          {:ok, backup} <- user |> new() |> Repo.insert() do
-      {:ok, backup}
+      Pleroma.Workers.BackupWorker.enqueue("process", %{"backup_id" => backup.id})
     end
   end
 
@@ -71,6 +71,15 @@ def get_last(user_id) do
     |> Repo.one()
   end
 
+  def remove_outdated(%__MODULE__{id: latest_id, user_id: user_id}) do
+    __MODULE__
+    |> where(user_id: ^user_id)
+    |> where([b], b.id != ^latest_id)
+    |> Repo.delete_all()
+  end
+
+  def get(id), do: Repo.get(__MODULE__, id)
+
   def process(%__MODULE__{} = backup) do
     with {:ok, zip_file} <- zip(backup),
          {:ok, %{size: size}} <- File.stat(zip_file),
diff --git a/lib/pleroma/workers/backup_worker.ex b/lib/pleroma/workers/backup_worker.ex
new file mode 100644
index 000000000..c982ffa3a
--- /dev/null
+++ b/lib/pleroma/workers/backup_worker.ex
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.BackupWorker do
+  alias Pleroma.Backup
+
+  use Pleroma.Workers.WorkerHelper, queue: "backup"
+
+  @impl Oban.Worker
+  def perform(%Job{args: %{"op" => "process", "backup_id" => backup_id}}) do
+    with {:ok, %Backup{} = backup} <-
+           backup_id |> Backup.get() |> Backup.process() do
+      {:ok, backup}
+    end
+  end
+end
diff --git a/test/backup_test.exs b/test/backup_test.exs
index 27f5cb7f7..5b1f76dd9 100644
--- a/test/backup_test.exs
+++ b/test/backup_test.exs
@@ -3,35 +3,43 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.BackupTest do
+  use Oban.Testing, repo: Pleroma.Repo
   use Pleroma.DataCase
+
   import Pleroma.Factory
   import Mock
 
   alias Pleroma.Backup
   alias Pleroma.Bookmark
   alias Pleroma.Web.CommonAPI
+  alias Pleroma.Workers.BackupWorker
 
-  test "it creates a backup record" do
+  setup do: clear_config([Pleroma.Upload, :uploader])
+
+  test "it creates a backup record and an Oban job" do
     %{id: user_id} = user = insert(:user)
-    assert {:ok, backup} = Backup.create(user)
+    assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
+    assert_enqueued(worker: BackupWorker, args: args)
 
+    backup = Backup.get(args["backup_id"])
     assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
   end
 
   test "it return an error if the export limit is over" do
     %{id: user_id} = user = insert(:user)
     limit_days = 7
-
-    assert {:ok, backup} = Backup.create(user)
+    assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
+    backup = Backup.get(args["backup_id"])
     assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
 
     assert Backup.create(user) == {:error, "Last export was less than #{limit_days} days ago"}
   end
 
   test "it process a backup record" do
+    Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
     %{id: user_id} = user = insert(:user)
-    assert {:ok, %{id: backup_id} = backup} = Backup.create(user)
-    assert {:ok, %Backup{} = backup} = Backup.process(backup)
+    assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id}} = job} = Backup.create(user)
+    assert {:ok, backup} = BackupWorker.perform(job)
     assert backup.file_size > 0
     assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
   end