diff --git a/packages/bbui/src/Form/Core/DatePicker.svelte b/packages/bbui/src/Form/Core/DatePicker.svelte
index 1a7ab59818..15200e111e 100644
--- a/packages/bbui/src/Form/Core/DatePicker.svelte
+++ b/packages/bbui/src/Form/Core/DatePicker.svelte
@@ -17,7 +17,7 @@
   export let timeOnly = false
   export let ignoreTimezones = false
   export let time24hr = false
-
+  export let range = false
   const dispatch = createEventDispatcher()
   const flatpickrId = `${uuid()}-wrapper`
   let open = false
@@ -41,6 +41,7 @@
     time_24hr: time24hr || false,
     altFormat: timeOnly ? "H:i" : enableTime ? "F j Y, H:i" : "F j, Y",
     wrap: true,
+    mode: range ? "range" : null,
     appendTo,
     disableMobile: "true",
     onReady: () => {
@@ -64,9 +65,8 @@
     if (newValue) {
       newValue = newValue.toISOString()
     }
-
     // If time only set date component to 2000-01-01
-    if (timeOnly) {
+    else if (timeOnly) {
       // Classic flackpickr causing issues.
       // When selecting a value for the first time for a "time only" field,
       // the time is always offset by 1 hour for some reason (regardless of time
@@ -95,7 +95,11 @@
         .slice(0, -1)
     }
 
-    dispatch("change", newValue)
+    if (range) {
+      dispatch("change", event.detail)
+    } else {
+      dispatch("change", newValue)
+    }
   }
 
   const clearDateOnBackspace = event => {
@@ -160,7 +164,7 @@
 {#key redrawOptions}
   <Flatpickr
     bind:flatpickr
-    value={parseDate(value)}
+    value={range ? value : parseDate(value)}
     on:open={onOpen}
     on:close={onClose}
     options={flatpickrOptions}
diff --git a/packages/bbui/src/Form/DatePicker.svelte b/packages/bbui/src/Form/DatePicker.svelte
index a0b102dbe8..04ce8b5467 100644
--- a/packages/bbui/src/Form/DatePicker.svelte
+++ b/packages/bbui/src/Form/DatePicker.svelte
@@ -14,11 +14,17 @@
   export let placeholder = null
   export let appendTo = undefined
   export let ignoreTimezones = false
-
+  export let range = false
   const dispatch = createEventDispatcher()
 
   const onChange = e => {
-    value = e.detail
+    if (range) {
+      // Flatpickr cant take two dates and work out what to display, needs to be provided a string.
+      // Like - "Date1 to Date2". Hence passing in that specifically from the array
+      value = e?.detail[1]
+    } else {
+      value = e.detail
+    }
     dispatch("change", e.detail)
   }
 </script>
@@ -34,6 +40,7 @@
     {time24hr}
     {appendTo}
     {ignoreTimezones}
+    {range}
     on:change={onChange}
   />
 </Field>
diff --git a/packages/bbui/src/Table/CellRenderer.svelte b/packages/bbui/src/Table/CellRenderer.svelte
index 246323244a..5004401d91 100644
--- a/packages/bbui/src/Table/CellRenderer.svelte
+++ b/packages/bbui/src/Table/CellRenderer.svelte
@@ -56,6 +56,7 @@
       {schema}
       value={cellValue}
       on:clickrelationship
+      on:buttonclick
     >
       <slot />
     </svelte:component>
diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte
index 01a2ca4835..7745c3c407 100644
--- a/packages/bbui/src/Table/Table.svelte
+++ b/packages/bbui/src/Table/Table.svelte
@@ -387,6 +387,7 @@
                   schema={schema[field]}
                   value={deepGet(row, field)}
                   on:clickrelationship
+                  on:buttonclick
                 >
                   <slot />
                 </CellRenderer>
diff --git a/packages/builder/assets/backups-default.png b/packages/builder/assets/backups-default.png
new file mode 100644
index 0000000000..6e37cbb6c7
Binary files /dev/null and b/packages/builder/assets/backups-default.png differ
diff --git a/packages/builder/src/components/portal/overview/backups/ActionsRenderer.svelte b/packages/builder/src/components/portal/overview/backups/ActionsRenderer.svelte
new file mode 100644
index 0000000000..b9ca38cf72
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/ActionsRenderer.svelte
@@ -0,0 +1,114 @@
+<script>
+  import {
+    ActionMenu,
+    MenuItem,
+    Icon,
+    Input,
+    Heading,
+    Body,
+    Modal,
+  } from "@budibase/bbui"
+  import ConfirmDialog from "components/common/ConfirmDialog.svelte"
+  import CreateRestoreModal from "./CreateRestoreModal.svelte"
+  import { createEventDispatcher } from "svelte"
+
+  export let row
+
+  let deleteDialog
+  let restoreDialog
+  let updateDialog
+  let name
+  let restoreBackupModal
+
+  const dispatch = createEventDispatcher()
+
+  const onClickRestore = name => {
+    dispatch("buttonclick", {
+      type: "backupRestore",
+      name,
+      backupId: row._id,
+      restoreBackupName: name,
+    })
+  }
+
+  const onClickDelete = () => {
+    dispatch("buttonclick", {
+      type: "backupDelete",
+      backupId: row._id,
+    })
+  }
+
+  const onClickUpdate = () => {
+    dispatch("buttonclick", {
+      type: "backupUpdate",
+      backupId: row._id,
+      name,
+    })
+  }
+
+  async function downloadExport() {
+    window.open(`/api/apps/${row.appId}/backups/${row._id}/file`, "_blank")
+  }
+</script>
+
+<div class="cell">
+  <ActionMenu align="right">
+    <div slot="control">
+      <Icon size="M" hoverable name="MoreSmallList" />
+    </div>
+
+    {#if row.type !== "restore"}
+      <MenuItem on:click={restoreDialog.show} icon="Revert">Restore</MenuItem>
+      <MenuItem on:click={deleteDialog.show} icon="Delete">Delete</MenuItem>
+      <MenuItem on:click={downloadExport} icon="Download">Download</MenuItem>
+    {/if}
+    <MenuItem on:click={updateDialog.show} icon="Edit">Update</MenuItem>
+  </ActionMenu>
+</div>
+
+<Modal bind:this={restoreBackupModal}>
+  <CreateRestoreModal confirm={name => onClickRestore(name)} />
+</Modal>
+
+<ConfirmDialog
+  bind:this={deleteDialog}
+  okText="Delete Backup"
+  onOk={onClickDelete}
+  title="Confirm Deletion"
+>
+  Are you sure you wish to delete the backup
+  <i>{row.name}</i>
+  This action cannot be undone.
+</ConfirmDialog>
+
+<ConfirmDialog
+  bind:this={restoreDialog}
+  okText="Continue"
+  onOk={restoreBackupModal?.show}
+  title="Confirm restore"
+  warning={false}
+>
+  <Heading size="S">{row.name || "Backup"}</Heading>
+  <Body size="S">{new Date(row.timestamp).toLocaleString()}</Body>
+</ConfirmDialog>
+
+<ConfirmDialog
+  bind:this={updateDialog}
+  disabled={!name}
+  okText="Confirm"
+  onOk={onClickUpdate}
+  title="Update Backup"
+  warning={false}
+>
+  <Input onlabel="Backup name" placeholder={row.name} bind:value={name} />
+</ConfirmDialog>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    gap: var(--spacing-m);
+    align-items: center;
+    margin-left: auto;
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/AppSizeRenderer.svelte b/packages/builder/src/components/portal/overview/backups/AppSizeRenderer.svelte
new file mode 100644
index 0000000000..c103399f5b
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/AppSizeRenderer.svelte
@@ -0,0 +1,41 @@
+<script>
+  import { Icon } from "@budibase/bbui"
+
+  export let row
+
+  $: automations = row?.automations
+  $: datasources = row?.datasources
+  $: screens = row?.screens
+</script>
+
+<div class="cell">
+  {#if automations != null && screens != null && datasources != null}
+    <div class="item">
+      <Icon name="Data" />
+      <div>{datasources || 0}</div>
+    </div>
+    <div class="item">
+      <Icon name="WebPage" />
+      <div>{screens || 0}</div>
+    </div>
+    <div class="item">
+      <Icon name="JourneyVoyager" />
+      <div>{automations || 0}</div>
+    </div>
+  {/if}
+</div>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    gap: calc(var(--spacing-xl) * 2);
+    align-items: center;
+  }
+
+  .item {
+    display: flex;
+    gap: var(--spacing-s);
+    flex-direction: row;
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/BackupsTab.svelte b/packages/builder/src/components/portal/overview/backups/BackupsTab.svelte
new file mode 100644
index 0000000000..958ee995c7
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/BackupsTab.svelte
@@ -0,0 +1,336 @@
+<script>
+  import {
+    ActionButton,
+    Button,
+    DatePicker,
+    Divider,
+    Layout,
+    Modal,
+    notifications,
+    Pagination,
+    Select,
+    Heading,
+    Body,
+    Tags,
+    Tag,
+    Table,
+    Page,
+  } from "@budibase/bbui"
+  import { backups, licensing, auth, admin } from "stores/portal"
+  import { createPaginationStore } from "helpers/pagination"
+  import AppSizeRenderer from "./AppSizeRenderer.svelte"
+  import CreateBackupModal from "./CreateBackupModal.svelte"
+  import ActionsRenderer from "./ActionsRenderer.svelte"
+  import DateRenderer from "./DateRenderer.svelte"
+  import UserRenderer from "./UserRenderer.svelte"
+  import StatusRenderer from "./StatusRenderer.svelte"
+  import TypeRenderer from "./TypeRenderer.svelte"
+  import BackupsDefault from "assets/backups-default.png"
+  import { onMount } from "svelte"
+
+  export let app
+
+  let backupData = null
+  let modal
+  let pageInfo = createPaginationStore()
+  let filterOpt = null
+  let startDate = null
+  let endDate = null
+  let filters = getFilters()
+
+  $: page = $pageInfo.page
+  $: fetchBackups(filterOpt, page, startDate, endDate)
+
+  function getFilters() {
+    const options = []
+    let types = ["backup"]
+    let triggers = ["manual", "publish", "scheduled", "restoring"]
+    for (let type of types) {
+      for (let trigger of triggers) {
+        let label = `${trigger} ${type}`
+        label = label.charAt(0).toUpperCase() + label?.slice(1)
+        options.push({ label, value: { type, trigger } })
+      }
+    }
+    options.push({
+      label: `Manual restore`,
+      value: { type: "restore", trigger: "manual" },
+    })
+    return options
+  }
+
+  const schema = {
+    type: {
+      displayName: "Type",
+    },
+    createdAt: {
+      displayName: "Date",
+    },
+    name: {
+      displayName: "Name",
+    },
+    appSize: {
+      displayName: "App size",
+    },
+    createdBy: {
+      displayName: "User",
+    },
+    status: {
+      displayName: "Status",
+    },
+    actions: {
+      displayName: null,
+    },
+  }
+
+  const customRenderers = [
+    { column: "appSize", component: AppSizeRenderer },
+    { column: "actions", component: ActionsRenderer },
+    { column: "createdAt", component: DateRenderer },
+    { column: "createdBy", component: UserRenderer },
+    { column: "status", component: StatusRenderer },
+    { column: "type", component: TypeRenderer },
+  ]
+
+  function flattenBackups(backups) {
+    return backups.map(backup => {
+      return {
+        ...backup,
+        ...backup?.contents,
+      }
+    })
+  }
+
+  async function fetchBackups(filters, page, startDate, endDate) {
+    const response = await backups.searchBackups({
+      appId: app.instance._id,
+      ...filters,
+      page,
+      startDate,
+      endDate,
+    })
+    pageInfo.fetched(response.hasNextPage, response.nextPage)
+
+    // flatten so we have an easier structure to use for the table schema
+    backupData = flattenBackups(response.data)
+  }
+
+  async function createManualBackup(name) {
+    try {
+      let response = await backups.createManualBackup({
+        appId: app.instance._id,
+        name,
+      })
+      await fetchBackups(filterOpt, page)
+      notifications.success(response.message)
+    } catch {
+      notifications.error("Unable to create backup")
+    }
+  }
+
+  async function handleButtonClick({ detail }) {
+    if (detail.type === "backupDelete") {
+      await backups.deleteBackup({
+        appId: app.instance._id,
+        backupId: detail.backupId,
+      })
+      await fetchBackups(filterOpt, page)
+    } else if (detail.type === "backupRestore") {
+      await backups.restoreBackup({
+        appId: app.instance._id,
+        backupId: detail.backupId,
+        name: detail.restoreBackupName,
+      })
+      await fetchBackups(filterOpt, page)
+    } else if (detail.type === "backupUpdate") {
+      await backups.updateBackup({
+        appId: app.instance._id,
+        backupId: detail.backupId,
+        name: detail.name,
+      })
+      await fetchBackups(filterOpt, page)
+    }
+  }
+
+  onMount(() => {
+    fetchBackups(filterOpt, page, startDate, endDate)
+  })
+</script>
+
+<div class="root">
+  {#if !$licensing.backupsEnabled}
+    <Page wide={false}>
+      <Layout gap="XS" noPadding>
+        <div class="title">
+          <Heading size="M">Backups</Heading>
+          <Tags>
+            <Tag icon="LockClosed">Pro plan</Tag>
+          </Tags>
+        </div>
+        <div>
+          <Body>
+            Backup your apps and restore them to their previous state.
+            {#if !$auth.accountPortalAccess && !$licensing.groupsEnabled && $admin.cloud}
+              Contact your account holder to upgrade your plan.
+            {/if}
+          </Body>
+        </div>
+        <Divider />
+        <div class="pro-buttons">
+          {#if $auth.accountPortalAccess}
+            <Button
+              newStyles
+              primary
+              disabled={!$auth.accountPortalAccess && $admin.cloud}
+              on:click={$licensing.goToUpgradePage()}
+            >
+              Upgrade
+            </Button>
+          {/if}
+          <!--Show the view plans button-->
+          <Button
+            newStyles
+            secondary
+            on:click={() => {
+              window.open("https://budibase.com/pricing/", "_blank")
+            }}
+          >
+            View Plans
+          </Button>
+        </div>
+      </Layout>
+    </Page>
+  {:else if backupData?.length > 0}
+    <Layout noPadding gap="M" alignContent="start">
+      <div class="search">
+        <div class="select">
+          <Select
+            placeholder="All"
+            label="Type"
+            options={filters}
+            getOptionValue={filter => filter.value}
+            getOptionLabel={filter => filter.label}
+            bind:value={filterOpt}
+          />
+        </div>
+        <div>
+          <DatePicker
+            range={true}
+            label={"Filter Range"}
+            on:change={e => {
+              if (e.detail[0].length > 1) {
+                startDate = e.detail[0][0].toISOString()
+                endDate = e.detail[0][1].toISOString()
+              }
+            }}
+          />
+        </div>
+
+        <div class="split-buttons">
+          <ActionButton on:click={modal.show} icon="SaveAsFloppy"
+            >Create new backup</ActionButton
+          >
+        </div>
+      </div>
+      <div>
+        <Table
+          {schema}
+          allowSelectRows={false}
+          allowEditColumns={false}
+          allowEditRows={false}
+          data={backupData}
+          {customRenderers}
+          placeholderText="No backups found"
+          border={false}
+          on:buttonclick={handleButtonClick}
+        />
+        <div class="pagination">
+          <Pagination
+            page={$pageInfo.pageNumber}
+            hasPrevPage={$pageInfo.loading ? false : $pageInfo.hasPrevPage}
+            hasNextPage={$pageInfo.loading ? false : $pageInfo.hasNextPage}
+            goToPrevPage={pageInfo.prevPage}
+            goToNextPage={pageInfo.nextPage}
+          />
+        </div>
+      </div>
+    </Layout>
+  {:else if backupData?.length === 0}
+    <Page wide={false}>
+      <div class="align">
+        <img
+          width="200px"
+          height="120px"
+          src={BackupsDefault}
+          alt="BackupsDefault"
+        />
+        <Layout gap="S">
+          <Heading>You have no backups yet</Heading>
+          <div class="opacity">
+            <Body size="S">You can manually backup your app any time</Body>
+          </div>
+          <div class="padding">
+            <Button on:click={modal.show} cta>Create Backup</Button>
+          </div>
+        </Layout>
+      </div>
+    </Page>
+  {/if}
+</div>
+
+<Modal bind:this={modal}>
+  <CreateBackupModal {createManualBackup} />
+</Modal>
+
+<style>
+  .root {
+    display: grid;
+    grid-template-columns: 1fr;
+    height: 100%;
+    padding: var(--spectrum-alias-grid-gutter-medium)
+      var(--spectrum-alias-grid-gutter-large);
+  }
+
+  .search {
+    display: flex;
+    gap: var(--spacing-xl);
+    width: 100%;
+    align-items: flex-end;
+  }
+
+  .select {
+    flex-basis: 150px;
+  }
+
+  .pagination {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    margin-top: var(--spacing-xl);
+  }
+
+  .split-buttons {
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    flex: 1;
+    gap: var(--spacing-xl);
+  }
+
+  .title {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    gap: var(--spacing-m);
+  }
+
+  .align {
+    margin-top: 5%;
+    text-align: center;
+  }
+
+  .pro-buttons {
+    display: flex;
+    gap: var(--spacing-m);
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/CreateBackupModal.svelte b/packages/builder/src/components/portal/overview/backups/CreateBackupModal.svelte
new file mode 100644
index 0000000000..d7a511890e
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/CreateBackupModal.svelte
@@ -0,0 +1,21 @@
+<script>
+  import { ModalContent, Input } from "@budibase/bbui"
+  import { auth } from "stores/portal"
+
+  export let createManualBackup
+
+  let templateName = $auth.user.firstName
+    ? `${$auth.user.firstName}'s Backup`
+    : "New Backup"
+  let name = templateName
+</script>
+
+<ModalContent
+  onConfirm={() => createManualBackup(name)}
+  title="Create new backup"
+  confirmText="Create"
+  ><Input label="Backup name" bind:value={name} /></ModalContent
+>
+
+<style>
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/CreateRestoreModal.svelte b/packages/builder/src/components/portal/overview/backups/CreateRestoreModal.svelte
new file mode 100644
index 0000000000..4ffb105772
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/CreateRestoreModal.svelte
@@ -0,0 +1,27 @@
+<script>
+  import { ModalContent, Input, Body } from "@budibase/bbui"
+  import { auth } from "stores/portal"
+
+  export let confirm
+
+  let templateName = $auth.user.firstName
+    ? `${$auth.user.firstName}'s Backup`
+    : "Restore Backup"
+  let name = templateName
+</script>
+
+<ModalContent
+  onConfirm={() => confirm(name)}
+  title="Backup your current version"
+  confirmText="Confirm Restore"
+  disabled={!name}
+>
+  <Body size="S"
+    >Create a backup of your current app to allow you to roll back after
+    restoring this backup</Body
+  >
+  <Input label="Backup name" bind:value={name} />
+</ModalContent>
+
+<style>
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/DatasourceRenderer.svelte b/packages/builder/src/components/portal/overview/backups/DatasourceRenderer.svelte
new file mode 100644
index 0000000000..198339dae9
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/DatasourceRenderer.svelte
@@ -0,0 +1,21 @@
+<script>
+  import { Icon } from "@budibase/bbui"
+
+  export let value
+</script>
+
+<div class="cell">
+  {#if value != null}
+    <Icon name="Data" />
+    <div>{value || 0}</div>
+  {/if}
+</div>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    gap: var(--spacing-m);
+    align-items: center;
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/DateRenderer.svelte b/packages/builder/src/components/portal/overview/backups/DateRenderer.svelte
new file mode 100644
index 0000000000..ec58c9ea07
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/DateRenderer.svelte
@@ -0,0 +1,22 @@
+<script>
+  import DateTimeRenderer from "components/common/renderers/DateTimeRenderer.svelte"
+  import dayjs from "dayjs"
+  import relativeTime from "dayjs/plugin/relativeTime"
+  dayjs.extend(relativeTime)
+
+  export let value
+  $: timeSince = dayjs(value).fromNow()
+</script>
+
+<div class="cell">
+  {timeSince} - <DateTimeRenderer {value} />
+</div>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    gap: var(--spacing-m);
+    align-items: center;
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/StatusRenderer.svelte b/packages/builder/src/components/portal/overview/backups/StatusRenderer.svelte
new file mode 100644
index 0000000000..3b3cce731d
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/StatusRenderer.svelte
@@ -0,0 +1,15 @@
+<script>
+  import { Badge } from "@budibase/bbui"
+
+  export let value = "started"
+  $: status = value[0].toUpperCase() + value?.slice(1)
+</script>
+
+<Badge
+  grey={value === "started" || value === "pending"}
+  green={value === "complete"}
+  red={value === "failed"}
+  size="S"
+>
+  {status}
+</Badge>
diff --git a/packages/builder/src/components/portal/overview/backups/TypeRenderer.svelte b/packages/builder/src/components/portal/overview/backups/TypeRenderer.svelte
new file mode 100644
index 0000000000..9057a2adee
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/TypeRenderer.svelte
@@ -0,0 +1,20 @@
+<script>
+  export let row
+
+  $: baseTrig = row?.trigger || "manual"
+  $: type = row?.type || "backup"
+  $: trigger = baseTrig.charAt(0).toUpperCase() + baseTrig.slice(1)
+</script>
+
+<div class="cell">
+  {trigger}
+  {type}
+</div>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+  }
+</style>
diff --git a/packages/builder/src/components/portal/overview/backups/UserRenderer.svelte b/packages/builder/src/components/portal/overview/backups/UserRenderer.svelte
new file mode 100644
index 0000000000..abab314d05
--- /dev/null
+++ b/packages/builder/src/components/portal/overview/backups/UserRenderer.svelte
@@ -0,0 +1,24 @@
+<script>
+  export let value
+
+  let firstName = value?.firstName
+  let lastName = value?.lastName || ""
+
+  $: username =
+    firstName && lastName ? `${firstName} ${lastName}` : value?.email
+</script>
+
+<div class="cell">
+  {#if value != null}
+    <div>{username}</div>
+  {/if}
+</div>
+
+<style>
+  .cell {
+    display: flex;
+    flex-direction: row;
+    gap: var(--spacing-m);
+    align-items: center;
+  }
+</style>
diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
index 5d25bba0fc..a854d09304 100644
--- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte
+++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte
@@ -113,18 +113,23 @@
           >
             Access
           </MenuItem>
-          {#if isPublished}
-            <MenuItem
-              on:click={() =>
-                $goto(
-                  `../../portal/overview/${application}?tab=${encodeURIComponent(
-                    "Automation History"
-                  )}`
-                )}
-            >
-              Automation history
-            </MenuItem>
-          {/if}
+          <MenuItem
+            on:click={() =>
+              $goto(
+                `../../portal/overview/${application}?tab=${encodeURIComponent(
+                  "Automation History"
+                )}`
+              )}
+          >
+            Automation history
+          </MenuItem>
+          <MenuItem
+            on:click={() =>
+              $goto(`../../portal/overview/${application}?tab=Backups`)}
+          >
+            Backups
+          </MenuItem>
+
           <MenuItem
             on:click={() =>
               $goto(`../../portal/overview/${application}?tab=Settings`)}
diff --git a/packages/builder/src/pages/builder/portal/overview/[application]/index.svelte b/packages/builder/src/pages/builder/portal/overview/[application]/index.svelte
index fe0e2443a2..cc31eec348 100644
--- a/packages/builder/src/pages/builder/portal/overview/[application]/index.svelte
+++ b/packages/builder/src/pages/builder/portal/overview/[application]/index.svelte
@@ -33,6 +33,7 @@
   import ExportAppModal from "components/start/ExportAppModal.svelte"
   import { checkIncomingDeploymentStatus } from "components/deploy/utils"
   import { onDestroy, onMount } from "svelte"
+  import BackupsTab from "components/portal/overview/backups/BackupsTab.svelte"
 
   export let application
 
@@ -318,16 +319,12 @@
           <Tab title="Access">
             <AccessTab app={selectedApp} />
           </Tab>
-          {#if isPublished}
-            <Tab title="Automation History">
-              <HistoryTab app={selectedApp} />
-            </Tab>
-          {/if}
-          {#if false}
-            <Tab title="Backups">
-              <div class="container">Backups contents</div>
-            </Tab>
-          {/if}
+          <Tab title="Automation History">
+            <HistoryTab app={selectedApp} />
+          </Tab>
+          <Tab title="Backups">
+            <BackupsTab app={selectedApp} />
+          </Tab>
           <Tab title="Settings">
             <SettingsTab app={selectedApp} />
           </Tab>
diff --git a/packages/builder/src/stores/portal/backups.js b/packages/builder/src/stores/portal/backups.js
new file mode 100644
index 0000000000..328a9d37cc
--- /dev/null
+++ b/packages/builder/src/stores/portal/backups.js
@@ -0,0 +1,52 @@
+import { writable } from "svelte/store"
+import { API } from "api"
+
+export function createBackupsStore() {
+  const store = writable({})
+
+  function selectBackup(backupId) {
+    store.update(state => {
+      state.selectedBackup = backupId
+      return state
+    })
+  }
+
+  async function searchBackups({
+    appId,
+    trigger,
+    type,
+    page,
+    startDate,
+    endDate,
+  }) {
+    return API.searchBackups({ appId, trigger, type, page, startDate, endDate })
+  }
+
+  async function restoreBackup({ appId, backupId, name }) {
+    return API.restoreBackup({ appId, backupId, name })
+  }
+
+  async function deleteBackup({ appId, backupId }) {
+    return API.deleteBackup({ appId, backupId })
+  }
+
+  async function createManualBackup(appId, name) {
+    return API.createManualBackup(appId, name)
+  }
+
+  async function updateBackup({ appId, backupId, name }) {
+    return API.updateBackup({ appId, backupId, name })
+  }
+
+  return {
+    createManualBackup,
+    searchBackups,
+    selectBackup,
+    deleteBackup,
+    restoreBackup,
+    updateBackup,
+    subscribe: store.subscribe,
+  }
+}
+
+export const backups = createBackupsStore()
diff --git a/packages/builder/src/stores/portal/index.js b/packages/builder/src/stores/portal/index.js
index fa7aa7e3cf..5406ddc3dc 100644
--- a/packages/builder/src/stores/portal/index.js
+++ b/packages/builder/src/stores/portal/index.js
@@ -9,3 +9,4 @@ export { templates } from "./templates"
 export { licensing } from "./licensing"
 export { groups } from "./groups"
 export { plugins } from "./plugins"
+export { backups } from "./backups"
diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js
index 179dac9689..59a1622c9f 100644
--- a/packages/builder/src/stores/portal/licensing.js
+++ b/packages/builder/src/stores/portal/licensing.js
@@ -14,6 +14,7 @@ export const createLicensingStore = () => {
     isFreePlan: true,
     // features
     groupsEnabled: false,
+    backupsEnabled: false,
     // the currently used quotas from the db
     quotaUsage: undefined,
     // derived quota metrics for percentages used
@@ -56,12 +57,17 @@ export const createLicensingStore = () => {
       const groupsEnabled = license.features.includes(
         Constants.Features.USER_GROUPS
       )
+      const backupsEnabled = license.features.includes(
+        Constants.Features.BACKUPS
+      )
+
       store.update(state => {
         return {
           ...state,
           license,
           isFreePlan,
           groupsEnabled,
+          backupsEnabled,
         }
       })
     },
diff --git a/packages/frontend-core/src/api/backups.js b/packages/frontend-core/src/api/backups.js
new file mode 100644
index 0000000000..8658815b15
--- /dev/null
+++ b/packages/frontend-core/src/api/backups.js
@@ -0,0 +1,50 @@
+export const buildBackupsEndpoints = API => ({
+  /**
+   * Gets a list of users in the current tenant.
+   */
+  searchBackups: async ({ appId, trigger, type, page, startDate, endDate }) => {
+    const opts = {}
+    if (page) {
+      opts.page = page
+    }
+    if (trigger && type) {
+      opts.trigger = trigger.toLowerCase()
+      opts.type = type.toLowerCase()
+    }
+    if (startDate && endDate) {
+      opts.startDate = startDate
+      opts.endDate = endDate
+    }
+    return await API.post({
+      url: `/api/apps/${appId}/backups/search`,
+      body: opts,
+    })
+  },
+
+  createManualBackup: async ({ appId, name }) => {
+    return await API.post({
+      url: `/api/apps/${appId}/backups`,
+      body: { name },
+    })
+  },
+
+  deleteBackup: async ({ appId, backupId }) => {
+    return await API.delete({
+      url: `/api/apps/${appId}/backups/${backupId}`,
+    })
+  },
+
+  updateBackup: async ({ appId, backupId, name }) => {
+    return await API.patch({
+      url: `/api/apps/${appId}/backups/${backupId}`,
+      body: { name },
+    })
+  },
+
+  restoreBackup: async ({ appId, backupId, name }) => {
+    return await API.post({
+      url: `/api/apps/${appId}/backups/${backupId}/import`,
+      body: { name },
+    })
+  },
+})
diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js
index 3b9bb5b57e..9a40b21351 100644
--- a/packages/frontend-core/src/api/index.js
+++ b/packages/frontend-core/src/api/index.js
@@ -25,6 +25,7 @@ import { buildViewEndpoints } from "./views"
 import { buildLicensingEndpoints } from "./licensing"
 import { buildGroupsEndpoints } from "./groups"
 import { buildPluginEndpoints } from "./plugins"
+import { buildBackupsEndpoints } from "./backups"
 
 const defaultAPIClientConfig = {
   /**
@@ -245,5 +246,6 @@ export const createAPIClient = config => {
     ...buildLicensingEndpoints(API),
     ...buildGroupsEndpoints(API),
     ...buildPluginEndpoints(API),
+    ...buildBackupsEndpoints(API),
   }
 }
diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js
index 9a5acf8a9b..1eed492c25 100644
--- a/packages/frontend-core/src/constants.js
+++ b/packages/frontend-core/src/constants.js
@@ -113,6 +113,7 @@ export const ApiVersion = "1"
 
 export const Features = {
   USER_GROUPS: "userGroups",
+  BACKUPS: "appBackups",
 }
 
 // Role IDs