diff --git a/packages/api/.gitignore b/packages/api/.gitignore
index f9f389e152042570ea69e1de23e999f442beec02..746647b4ea792bec66f98e64504321490a5c312d 100644
--- a/packages/api/.gitignore
+++ b/packages/api/.gitignore
@@ -1 +1,3 @@
 app/bundle.api.js*
+migrations
+default-db.sqlite
diff --git a/packages/api/default-db.sqlite b/packages/api/default-db.sqlite
deleted file mode 100644
index 5d55b361144e7ea59d64496977edffc50819ebe2..0000000000000000000000000000000000000000
Binary files a/packages/api/default-db.sqlite and /dev/null differ
diff --git a/packages/api/migrations/.force-copy-windows b/packages/api/migrations/.force-copy-windows
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/packages/api/migrations/1548957970627_remove-db-version.sql b/packages/api/migrations/1548957970627_remove-db-version.sql
deleted file mode 100644
index d93af5d93de1625aeb321faba69b420af22ebe3d..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1548957970627_remove-db-version.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN TRANSACTION;
-
-DROP TABLE db_version;
-
-COMMIT;
diff --git a/packages/api/migrations/1550601598648_payees.sql b/packages/api/migrations/1550601598648_payees.sql
deleted file mode 100644
index 9cab9504711646edae67de6e2f918a726ce6c6fd..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1550601598648_payees.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE payees
-  (id TEXT PRIMARY KEY,
-   name TEXT,
-   category TEXT,
-   tombstone INTEGER DEFAULT 0,
-   transfer_acct TEXT);
-
-CREATE TABLE payee_rules
-  (id TEXT PRIMARY KEY,
-   payee_id TEXT,
-   type TEXT,
-   value TEXT,
-   tombstone INTEGER DEFAULT 0);
-
-CREATE INDEX payee_rules_lowercase_index ON payee_rules(LOWER(value));
-
-CREATE TABLE payee_mapping
-  (id TEXT PRIMARY KEY,
-   targetId TEXT);
-
-COMMIT;
diff --git a/packages/api/migrations/1555786194328_remove_category_group_unique.sql b/packages/api/migrations/1555786194328_remove_category_group_unique.sql
deleted file mode 100644
index f97e2d741703b02dfadf7d543ff593c30e788127..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1555786194328_remove_category_group_unique.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TEMPORARY TABLE category_groups_tmp
-   (id TEXT PRIMARY KEY,
-    name TEXT UNIQUE,
-    is_income INTEGER DEFAULT 0,
-    sort_order REAL,
-    tombstone INTEGER DEFAULT 0);
-
-INSERT INTO category_groups_tmp SELECT * FROM category_groups;
-
-DROP TABLE category_groups;
-
-CREATE TABLE category_groups
-   (id TEXT PRIMARY KEY,
-    name TEXT,
-    is_income INTEGER DEFAULT 0,
-    sort_order REAL,
-    tombstone INTEGER DEFAULT 0);
-
-INSERT INTO category_groups SELECT * FROM category_groups_tmp;
-
-DROP TABLE category_groups_tmp;
-
-COMMIT;
diff --git a/packages/api/migrations/1561751833510_indexes.sql b/packages/api/migrations/1561751833510_indexes.sql
deleted file mode 100644
index 733dfa5d2cee20dd7a7087ebfa0f875ca82519df..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1561751833510_indexes.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE INDEX trans_category_date ON transactions(category, date);
-CREATE INDEX trans_category ON transactions(category);
-CREATE INDEX trans_date ON transactions(date);
-
-COMMIT;
diff --git a/packages/api/migrations/1567699552727_budget.sql b/packages/api/migrations/1567699552727_budget.sql
deleted file mode 100644
index 6f0519da629003c1e4a35575965df119644999ec..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1567699552727_budget.sql
+++ /dev/null
@@ -1,38 +0,0 @@
-BEGIN TRANSACTION;
-
-DELETE FROM spreadsheet_cells WHERE
-  name NOT LIKE '%!budget\_%' ESCAPE '\' AND
-  name NOT LIKE '%!carryover\_%' ESCAPE '\' AND
-  name NOT LIKE '%!buffered';
-
-UPDATE OR REPLACE spreadsheet_cells SET name = REPLACE(name, '_', '-');
-
-UPDATE OR REPLACE spreadsheet_cells SET
-  name =
-    SUBSTR(name, 1, 28) ||
-    '-' ||
-    SUBSTR(name, 29, 4) ||
-    '-' ||
-    SUBSTR(name, 33, 4) ||
-    '-' ||
-    SUBSTR(name, 37, 4) ||
-    '-' ||
-    SUBSTR(name, 41, 12)
-WHERE name LIKE '%!budget-%' AND LENGTH(name) = 52;
-
-UPDATE OR REPLACE spreadsheet_cells SET
-  name =
-    SUBSTR(name, 1, 31) ||
-    '-' ||
-    SUBSTR(name, 32, 4) ||
-    '-' ||
-    SUBSTR(name, 36, 4) ||
-    '-' ||
-    SUBSTR(name, 40, 4) ||
-    '-' ||
-    SUBSTR(name, 44, 12)
-WHERE name LIKE '%!carryover-%' AND LENGTH(name) = 55;
-
-UPDATE spreadsheet_cells SET expr = SUBSTR(expr, 2) WHERE name LIKE '%!carryover-%';
-
-COMMIT;
diff --git a/packages/api/migrations/1582384163573_cleared.sql b/packages/api/migrations/1582384163573_cleared.sql
deleted file mode 100644
index 5d6f8ce662e70e0c8961eb422acacd479fa13f06..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1582384163573_cleared.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE transactions ADD COLUMN cleared INTEGER DEFAULT 1;
-ALTER TABLE transactions ADD COLUMN pending INTEGER DEFAULT 0;
-
-COMMIT;
diff --git a/packages/api/migrations/1597756566448_rules.sql b/packages/api/migrations/1597756566448_rules.sql
deleted file mode 100644
index 291e2b1beb0926a8f277b334853683373b4bcae2..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1597756566448_rules.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE rules
-  (id TEXT PRIMARY KEY,
-   stage TEXT,
-   conditions TEXT,
-   actions TEXT,
-   tombstone INTEGER DEFAULT 0);
-
-COMMIT;
diff --git a/packages/api/migrations/1608652596043_parent_field.sql b/packages/api/migrations/1608652596043_parent_field.sql
deleted file mode 100644
index a5bdf8796e8b482a58624ac95eda0f559ce2f91b..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1608652596043_parent_field.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE transactions ADD COLUMN parent_id TEXT;
-
-UPDATE transactions SET
-  parent_id = CASE
-    WHEN isChild THEN SUBSTR(id, 1, INSTR(id, '/') - 1)
-    ELSE NULL
-  END;
-
-CREATE INDEX trans_parent_id ON transactions(parent_id);
-
-COMMIT;
diff --git a/packages/api/migrations/1608652596044_trans_views.sql b/packages/api/migrations/1608652596044_trans_views.sql
deleted file mode 100644
index 345fc234da0713edd8cc156575aaddf1257518f8..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1608652596044_trans_views.sql
+++ /dev/null
@@ -1,56 +0,0 @@
-BEGIN TRANSACTION;
-
-DROP VIEW IF EXISTS v_transactions_layer2;
-CREATE VIEW v_transactions_layer2 AS
-SELECT
-  t.id AS id,
-  t.isParent AS is_parent,
-  t.isChild AS is_child,
-  t.acct AS account,
-  CASE WHEN t.isChild = 0 THEN NULL ELSE t.parent_id END AS parent_id,
-  CASE WHEN t.isParent = 1 THEN NULL ELSE cm.transferId END AS category,
-  pm.targetId AS payee,
-  t.imported_description AS imported_payee,
-  IFNULL(t.amount, 0) AS amount,
-  t.notes AS notes,
-  t.date AS date,
-  t.financial_id AS imported_id,
-  t.error AS error,
-  t.starting_balance_flag AS starting_balance_flag,
-  t.transferred_id AS transfer_id,
-  t.sort_order AS sort_order,
-  t.cleared AS cleared,
-  t.tombstone AS tombstone
-FROM transactions t
-LEFT JOIN category_mapping cm ON cm.id = t.category
-LEFT JOIN payee_mapping pm ON pm.id = t.description
-WHERE
-  t.date IS NOT NULL AND
-  t.acct IS NOT NULL;
-
-CREATE INDEX trans_sorted ON transactions(date desc, starting_balance_flag, sort_order desc, id);
-
-DROP VIEW IF EXISTS v_transactions_layer1;
-CREATE VIEW v_transactions_layer1 AS
-SELECT t.* FROM v_transactions_layer2 t
-LEFT JOIN transactions t2 ON (t.is_child = 1 AND t2.id = t.parent_id)
-WHERE IFNULL(t.tombstone, 0) = 0 AND IFNULL(t2.tombstone, 0) = 0;
-
-DROP VIEW IF EXISTS v_transactions;
-CREATE VIEW v_transactions AS
-SELECT t.* FROM v_transactions_layer1 t
-ORDER BY t.date desc, t.starting_balance_flag, t.sort_order desc, t.id;
-
-
-DROP VIEW IF EXISTS v_categories;
-CREATE VIEW v_categories AS
-SELECT
-  id,
-  name,
-  is_income,
-  cat_group AS "group",
-  sort_order,
-  tombstone
-FROM categories;
-
-COMMIT;
diff --git a/packages/api/migrations/1612625548236_optimize.sql b/packages/api/migrations/1612625548236_optimize.sql
deleted file mode 100644
index 6e7075ff0e8c69aaa9674a95d485850d844aade2..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1612625548236_optimize.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE INDEX messages_crdt_search ON messages_crdt(dataset, row, column, timestamp);
-
-ANALYZE;
-
-COMMIT;
diff --git a/packages/api/migrations/1614782639336_trans_views2.sql b/packages/api/migrations/1614782639336_trans_views2.sql
deleted file mode 100644
index c95a92ca6e87ff09d6c5adc72916e1089c3e14c8..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1614782639336_trans_views2.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-BEGIN TRANSACTION;
-
--- This adds the isChild/parent_id constraint in `where`
-DROP VIEW IF EXISTS v_transactions_layer2;
-CREATE VIEW v_transactions_layer2 AS
-SELECT
-  t.id AS id,
-  t.isParent AS is_parent,
-  t.isChild AS is_child,
-  t.acct AS account,
-  CASE WHEN t.isChild = 0 THEN NULL ELSE t.parent_id END AS parent_id,
-  CASE WHEN t.isParent = 1 THEN NULL ELSE cm.transferId END AS category,
-  pm.targetId AS payee,
-  t.imported_description AS imported_payee,
-  IFNULL(t.amount, 0) AS amount,
-  t.notes AS notes,
-  t.date AS date,
-  t.financial_id AS imported_id,
-  t.error AS error,
-  t.starting_balance_flag AS starting_balance_flag,
-  t.transferred_id AS transfer_id,
-  t.sort_order AS sort_order,
-  t.cleared AS cleared,
-  t.tombstone AS tombstone
-FROM transactions t
-LEFT JOIN category_mapping cm ON cm.id = t.category
-LEFT JOIN payee_mapping pm ON pm.id = t.description
-WHERE
-  t.date IS NOT NULL AND
-  t.acct IS NOT NULL AND
-  (t.isChild = 0 OR t.parent_id IS NOT NULL);
-
-COMMIT;
diff --git a/packages/api/migrations/1615745967948_meta.sql b/packages/api/migrations/1615745967948_meta.sql
deleted file mode 100644
index 6bcb3d76f796ab8724773f658ee95ea65f48c739..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1615745967948_meta.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE __meta__ (key TEXT PRIMARY KEY, value TEXT);
-
-DROP VIEW IF EXISTS v_transactions_layer2;
-DROP VIEW IF EXISTS v_transactions_layer1;
-DROP VIEW IF EXISTS v_transactions;
-DROP VIEW IF EXISTS v_categories;
-
-COMMIT;
diff --git a/packages/api/migrations/1616167010796_accounts_order.sql b/packages/api/migrations/1616167010796_accounts_order.sql
deleted file mode 100644
index 6e259794a1a1ad7551f7913f51e227d6ad3e8895..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1616167010796_accounts_order.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE accounts ADD COLUMN sort_order REAL;
-
-COMMIT;
diff --git a/packages/api/migrations/1618975177358_schedules.sql b/packages/api/migrations/1618975177358_schedules.sql
deleted file mode 100644
index 6c57a5d1403311f7e3fb47dd4ba34bbb9d39253b..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1618975177358_schedules.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE schedules
-  (id TEXT PRIMARY KEY,
-   rule TEXT,
-   active INTEGER DEFAULT 0,
-   completed INTEGER DEFAULT 0,
-   posts_transaction INTEGER DEFAULT 0,
-   tombstone INTEGER DEFAULT 0);
-
-CREATE TABLE schedules_next_date
-  (id TEXT PRIMARY KEY,
-   schedule_id TEXT,
-   local_next_date INTEGER,
-   local_next_date_ts INTEGER,
-   base_next_date INTEGER,
-   base_next_date_ts INTEGER);
-
-CREATE TABLE schedules_json_paths
-  (schedule_id TEXT PRIMARY KEY,
-   payee TEXT,
-   account TEXT,
-   amount TEXT,
-   date TEXT);
-
-ALTER TABLE transactions ADD COLUMN schedule TEXT;
-
-COMMIT;
diff --git a/packages/api/migrations/1632571489012_remove_cache.js b/packages/api/migrations/1632571489012_remove_cache.js
deleted file mode 100644
index 2f3764c47dee15b631b96c3f8a95880ff9a101b9..0000000000000000000000000000000000000000
--- a/packages/api/migrations/1632571489012_remove_cache.js
+++ /dev/null
@@ -1,135 +0,0 @@
-export default async function runMigration(db, uuid) {
-  function getValue(node) {
-    return node.expr != null ? node.expr : node.cachedValue;
-  }
-
-  db.execQuery(`
-CREATE TABLE zero_budget_months
-  (id TEXT PRIMARY KEY,
-   buffered INTEGER DEFAULT 0);
-
-CREATE TABLE zero_budgets
-  (id TEXT PRIMARY KEY,
-   month INTEGER,
-   category TEXT,
-   amount INTEGER DEFAULT 0,
-   carryover INTEGER DEFAULT 0);
-
-CREATE TABLE reflect_budgets
-  (id TEXT PRIMARY KEY,
-   month INTEGER,
-   category TEXT,
-   amount INTEGER DEFAULT 0,
-   carryover INTEGER DEFAULT 0);
-
-CREATE TABLE notes
-  (id TEXT PRIMARY KEY,
-   note TEXT);
-
-CREATE TABLE kvcache (key TEXT PRIMARY KEY, value TEXT);
-CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
-`);
-
-  // Migrate budget amounts and carryover
-  let budget = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!budget-%'`,
-    [],
-    true,
-  );
-  db.transaction(() => {
-    budget.forEach(monthBudget => {
-      let match = monthBudget.name.match(
-        /^(budget-report|budget)(\d+)!budget-(.+)$/,
-      );
-      if (match == null) {
-        console.log('Warning: invalid budget month name', monthBudget.name);
-        return;
-      }
-
-      let type = match[1];
-      let month = match[2].slice(0, 4) + '-' + match[2].slice(4);
-      let dbmonth = parseInt(match[2]);
-      let cat = match[3];
-
-      let amount = parseInt(getValue(monthBudget));
-      if (isNaN(amount)) {
-        amount = 0;
-      }
-
-      let sheetName = monthBudget.name.split('!')[0];
-      let carryover = db.runQuery(
-        'SELECT * FROM spreadsheet_cells WHERE name = ?',
-        [`${sheetName}!carryover-${cat}`],
-        true,
-      );
-
-      let table = type === 'budget-report' ? 'reflect_budgets' : 'zero_budgets';
-      db.runQuery(
-        `INSERT INTO ${table} (id, month, category, amount, carryover) VALUES (?, ?, ?, ?, ?)`,
-        [
-          `${month}-${cat}`,
-          dbmonth,
-          cat,
-          amount,
-          carryover.length > 0 && getValue(carryover[0]) === 'true' ? 1 : 0,
-        ],
-      );
-    });
-  });
-
-  // Migrate buffers
-  let buffers = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!buffered'`,
-    [],
-    true,
-  );
-  db.transaction(() => {
-    buffers.forEach(buffer => {
-      let match = buffer.name.match(/^budget(\d+)!buffered$/);
-      if (match) {
-        let month = match[1].slice(0, 4) + '-' + match[1].slice(4);
-        let amount = parseInt(getValue(buffer));
-        if (isNaN(amount)) {
-          amount = 0;
-        }
-
-        db.runQuery(
-          `INSERT INTO zero_budget_months (id, buffered) VALUES (?, ?)`,
-          [month, amount],
-        );
-      }
-    });
-  });
-
-  // Migrate notes
-  let notes = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'notes!%'`,
-    [],
-    true,
-  );
-
-  let parseNote = str => {
-    try {
-      let value = JSON.parse(str);
-      return value && value !== '' ? value : null;
-    } catch (e) {
-      return null;
-    }
-  };
-
-  db.transaction(() => {
-    notes.forEach(note => {
-      let parsed = parseNote(getValue(note));
-      if (parsed) {
-        let [, id] = note.name.split('!');
-        db.runQuery(`INSERT INTO notes (id, note) VALUES (?, ?)`, [id, parsed]);
-      }
-    });
-  });
-
-  db.execQuery(`
-    DROP TABLE spreadsheet_cells;
-    ANALYZE;
-    VACUUM;
-  `);
-}
diff --git a/packages/desktop-client/.gitignore b/packages/desktop-client/.gitignore
index ddec6994d221f5596d7c6203ab78e4a8719ec7a2..652b554f3f200819b31f89b5e1b6a78c7da639d6 100644
--- a/packages/desktop-client/.gitignore
+++ b/packages/desktop-client/.gitignore
@@ -17,3 +17,5 @@ npm-debug.log
 
 *kcab.*
 public/kcab
+public/data
+public/data-file-index.txt
diff --git a/packages/desktop-client/public/data-file-index.txt b/packages/desktop-client/public/data-file-index.txt
deleted file mode 100644
index edb2dce0978389e1c5f5d803b14b1c41974ea9a7..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data-file-index.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-default-db.sqlite
-migrations/.force-copy-windows
-migrations/1548957970627_remove-db-version.sql
-migrations/1550601598648_payees.sql
-migrations/1555786194328_remove_category_group_unique.sql
-migrations/1561751833510_indexes.sql
-migrations/1567699552727_budget.sql
-migrations/1582384163573_cleared.sql
-migrations/1597756566448_rules.sql
-migrations/1608652596043_parent_field.sql
-migrations/1608652596044_trans_views.sql
-migrations/1612625548236_optimize.sql
-migrations/1614782639336_trans_views2.sql
-migrations/1615745967948_meta.sql
-migrations/1616167010796_accounts_order.sql
-migrations/1618975177358_schedules.sql
-migrations/1632571489012_remove_cache.js
-migrations/1679728867040_rules_conditions.sql
diff --git a/packages/desktop-client/public/data/default-db.sqlite b/packages/desktop-client/public/data/default-db.sqlite
deleted file mode 100644
index 5d55b361144e7ea59d64496977edffc50819ebe2..0000000000000000000000000000000000000000
Binary files a/packages/desktop-client/public/data/default-db.sqlite and /dev/null differ
diff --git a/packages/desktop-client/public/data/migrations/.force-copy-windows b/packages/desktop-client/public/data/migrations/.force-copy-windows
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/packages/desktop-client/public/data/migrations/1548957970627_remove-db-version.sql b/packages/desktop-client/public/data/migrations/1548957970627_remove-db-version.sql
deleted file mode 100644
index d93af5d93de1625aeb321faba69b420af22ebe3d..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1548957970627_remove-db-version.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN TRANSACTION;
-
-DROP TABLE db_version;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1550601598648_payees.sql b/packages/desktop-client/public/data/migrations/1550601598648_payees.sql
deleted file mode 100644
index 9cab9504711646edae67de6e2f918a726ce6c6fd..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1550601598648_payees.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE payees
-  (id TEXT PRIMARY KEY,
-   name TEXT,
-   category TEXT,
-   tombstone INTEGER DEFAULT 0,
-   transfer_acct TEXT);
-
-CREATE TABLE payee_rules
-  (id TEXT PRIMARY KEY,
-   payee_id TEXT,
-   type TEXT,
-   value TEXT,
-   tombstone INTEGER DEFAULT 0);
-
-CREATE INDEX payee_rules_lowercase_index ON payee_rules(LOWER(value));
-
-CREATE TABLE payee_mapping
-  (id TEXT PRIMARY KEY,
-   targetId TEXT);
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1555786194328_remove_category_group_unique.sql b/packages/desktop-client/public/data/migrations/1555786194328_remove_category_group_unique.sql
deleted file mode 100644
index f97e2d741703b02dfadf7d543ff593c30e788127..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1555786194328_remove_category_group_unique.sql
+++ /dev/null
@@ -1,25 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TEMPORARY TABLE category_groups_tmp
-   (id TEXT PRIMARY KEY,
-    name TEXT UNIQUE,
-    is_income INTEGER DEFAULT 0,
-    sort_order REAL,
-    tombstone INTEGER DEFAULT 0);
-
-INSERT INTO category_groups_tmp SELECT * FROM category_groups;
-
-DROP TABLE category_groups;
-
-CREATE TABLE category_groups
-   (id TEXT PRIMARY KEY,
-    name TEXT,
-    is_income INTEGER DEFAULT 0,
-    sort_order REAL,
-    tombstone INTEGER DEFAULT 0);
-
-INSERT INTO category_groups SELECT * FROM category_groups_tmp;
-
-DROP TABLE category_groups_tmp;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1561751833510_indexes.sql b/packages/desktop-client/public/data/migrations/1561751833510_indexes.sql
deleted file mode 100644
index 733dfa5d2cee20dd7a7087ebfa0f875ca82519df..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1561751833510_indexes.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE INDEX trans_category_date ON transactions(category, date);
-CREATE INDEX trans_category ON transactions(category);
-CREATE INDEX trans_date ON transactions(date);
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1567699552727_budget.sql b/packages/desktop-client/public/data/migrations/1567699552727_budget.sql
deleted file mode 100644
index 6f0519da629003c1e4a35575965df119644999ec..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1567699552727_budget.sql
+++ /dev/null
@@ -1,38 +0,0 @@
-BEGIN TRANSACTION;
-
-DELETE FROM spreadsheet_cells WHERE
-  name NOT LIKE '%!budget\_%' ESCAPE '\' AND
-  name NOT LIKE '%!carryover\_%' ESCAPE '\' AND
-  name NOT LIKE '%!buffered';
-
-UPDATE OR REPLACE spreadsheet_cells SET name = REPLACE(name, '_', '-');
-
-UPDATE OR REPLACE spreadsheet_cells SET
-  name =
-    SUBSTR(name, 1, 28) ||
-    '-' ||
-    SUBSTR(name, 29, 4) ||
-    '-' ||
-    SUBSTR(name, 33, 4) ||
-    '-' ||
-    SUBSTR(name, 37, 4) ||
-    '-' ||
-    SUBSTR(name, 41, 12)
-WHERE name LIKE '%!budget-%' AND LENGTH(name) = 52;
-
-UPDATE OR REPLACE spreadsheet_cells SET
-  name =
-    SUBSTR(name, 1, 31) ||
-    '-' ||
-    SUBSTR(name, 32, 4) ||
-    '-' ||
-    SUBSTR(name, 36, 4) ||
-    '-' ||
-    SUBSTR(name, 40, 4) ||
-    '-' ||
-    SUBSTR(name, 44, 12)
-WHERE name LIKE '%!carryover-%' AND LENGTH(name) = 55;
-
-UPDATE spreadsheet_cells SET expr = SUBSTR(expr, 2) WHERE name LIKE '%!carryover-%';
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1582384163573_cleared.sql b/packages/desktop-client/public/data/migrations/1582384163573_cleared.sql
deleted file mode 100644
index 5d6f8ce662e70e0c8961eb422acacd479fa13f06..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1582384163573_cleared.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE transactions ADD COLUMN cleared INTEGER DEFAULT 1;
-ALTER TABLE transactions ADD COLUMN pending INTEGER DEFAULT 0;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1597756566448_rules.sql b/packages/desktop-client/public/data/migrations/1597756566448_rules.sql
deleted file mode 100644
index 291e2b1beb0926a8f277b334853683373b4bcae2..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1597756566448_rules.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE rules
-  (id TEXT PRIMARY KEY,
-   stage TEXT,
-   conditions TEXT,
-   actions TEXT,
-   tombstone INTEGER DEFAULT 0);
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1608652596043_parent_field.sql b/packages/desktop-client/public/data/migrations/1608652596043_parent_field.sql
deleted file mode 100644
index a5bdf8796e8b482a58624ac95eda0f559ce2f91b..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1608652596043_parent_field.sql
+++ /dev/null
@@ -1,13 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE transactions ADD COLUMN parent_id TEXT;
-
-UPDATE transactions SET
-  parent_id = CASE
-    WHEN isChild THEN SUBSTR(id, 1, INSTR(id, '/') - 1)
-    ELSE NULL
-  END;
-
-CREATE INDEX trans_parent_id ON transactions(parent_id);
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1608652596044_trans_views.sql b/packages/desktop-client/public/data/migrations/1608652596044_trans_views.sql
deleted file mode 100644
index 345fc234da0713edd8cc156575aaddf1257518f8..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1608652596044_trans_views.sql
+++ /dev/null
@@ -1,56 +0,0 @@
-BEGIN TRANSACTION;
-
-DROP VIEW IF EXISTS v_transactions_layer2;
-CREATE VIEW v_transactions_layer2 AS
-SELECT
-  t.id AS id,
-  t.isParent AS is_parent,
-  t.isChild AS is_child,
-  t.acct AS account,
-  CASE WHEN t.isChild = 0 THEN NULL ELSE t.parent_id END AS parent_id,
-  CASE WHEN t.isParent = 1 THEN NULL ELSE cm.transferId END AS category,
-  pm.targetId AS payee,
-  t.imported_description AS imported_payee,
-  IFNULL(t.amount, 0) AS amount,
-  t.notes AS notes,
-  t.date AS date,
-  t.financial_id AS imported_id,
-  t.error AS error,
-  t.starting_balance_flag AS starting_balance_flag,
-  t.transferred_id AS transfer_id,
-  t.sort_order AS sort_order,
-  t.cleared AS cleared,
-  t.tombstone AS tombstone
-FROM transactions t
-LEFT JOIN category_mapping cm ON cm.id = t.category
-LEFT JOIN payee_mapping pm ON pm.id = t.description
-WHERE
-  t.date IS NOT NULL AND
-  t.acct IS NOT NULL;
-
-CREATE INDEX trans_sorted ON transactions(date desc, starting_balance_flag, sort_order desc, id);
-
-DROP VIEW IF EXISTS v_transactions_layer1;
-CREATE VIEW v_transactions_layer1 AS
-SELECT t.* FROM v_transactions_layer2 t
-LEFT JOIN transactions t2 ON (t.is_child = 1 AND t2.id = t.parent_id)
-WHERE IFNULL(t.tombstone, 0) = 0 AND IFNULL(t2.tombstone, 0) = 0;
-
-DROP VIEW IF EXISTS v_transactions;
-CREATE VIEW v_transactions AS
-SELECT t.* FROM v_transactions_layer1 t
-ORDER BY t.date desc, t.starting_balance_flag, t.sort_order desc, t.id;
-
-
-DROP VIEW IF EXISTS v_categories;
-CREATE VIEW v_categories AS
-SELECT
-  id,
-  name,
-  is_income,
-  cat_group AS "group",
-  sort_order,
-  tombstone
-FROM categories;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1612625548236_optimize.sql b/packages/desktop-client/public/data/migrations/1612625548236_optimize.sql
deleted file mode 100644
index 6e7075ff0e8c69aaa9674a95d485850d844aade2..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1612625548236_optimize.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE INDEX messages_crdt_search ON messages_crdt(dataset, row, column, timestamp);
-
-ANALYZE;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1614782639336_trans_views2.sql b/packages/desktop-client/public/data/migrations/1614782639336_trans_views2.sql
deleted file mode 100644
index c95a92ca6e87ff09d6c5adc72916e1089c3e14c8..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1614782639336_trans_views2.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-BEGIN TRANSACTION;
-
--- This adds the isChild/parent_id constraint in `where`
-DROP VIEW IF EXISTS v_transactions_layer2;
-CREATE VIEW v_transactions_layer2 AS
-SELECT
-  t.id AS id,
-  t.isParent AS is_parent,
-  t.isChild AS is_child,
-  t.acct AS account,
-  CASE WHEN t.isChild = 0 THEN NULL ELSE t.parent_id END AS parent_id,
-  CASE WHEN t.isParent = 1 THEN NULL ELSE cm.transferId END AS category,
-  pm.targetId AS payee,
-  t.imported_description AS imported_payee,
-  IFNULL(t.amount, 0) AS amount,
-  t.notes AS notes,
-  t.date AS date,
-  t.financial_id AS imported_id,
-  t.error AS error,
-  t.starting_balance_flag AS starting_balance_flag,
-  t.transferred_id AS transfer_id,
-  t.sort_order AS sort_order,
-  t.cleared AS cleared,
-  t.tombstone AS tombstone
-FROM transactions t
-LEFT JOIN category_mapping cm ON cm.id = t.category
-LEFT JOIN payee_mapping pm ON pm.id = t.description
-WHERE
-  t.date IS NOT NULL AND
-  t.acct IS NOT NULL AND
-  (t.isChild = 0 OR t.parent_id IS NOT NULL);
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1615745967948_meta.sql b/packages/desktop-client/public/data/migrations/1615745967948_meta.sql
deleted file mode 100644
index 6bcb3d76f796ab8724773f658ee95ea65f48c739..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1615745967948_meta.sql
+++ /dev/null
@@ -1,10 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE __meta__ (key TEXT PRIMARY KEY, value TEXT);
-
-DROP VIEW IF EXISTS v_transactions_layer2;
-DROP VIEW IF EXISTS v_transactions_layer1;
-DROP VIEW IF EXISTS v_transactions;
-DROP VIEW IF EXISTS v_categories;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1616167010796_accounts_order.sql b/packages/desktop-client/public/data/migrations/1616167010796_accounts_order.sql
deleted file mode 100644
index 6e259794a1a1ad7551f7913f51e227d6ad3e8895..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1616167010796_accounts_order.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE accounts ADD COLUMN sort_order REAL;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1618975177358_schedules.sql b/packages/desktop-client/public/data/migrations/1618975177358_schedules.sql
deleted file mode 100644
index 6c57a5d1403311f7e3fb47dd4ba34bbb9d39253b..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1618975177358_schedules.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE schedules
-  (id TEXT PRIMARY KEY,
-   rule TEXT,
-   active INTEGER DEFAULT 0,
-   completed INTEGER DEFAULT 0,
-   posts_transaction INTEGER DEFAULT 0,
-   tombstone INTEGER DEFAULT 0);
-
-CREATE TABLE schedules_next_date
-  (id TEXT PRIMARY KEY,
-   schedule_id TEXT,
-   local_next_date INTEGER,
-   local_next_date_ts INTEGER,
-   base_next_date INTEGER,
-   base_next_date_ts INTEGER);
-
-CREATE TABLE schedules_json_paths
-  (schedule_id TEXT PRIMARY KEY,
-   payee TEXT,
-   account TEXT,
-   amount TEXT,
-   date TEXT);
-
-ALTER TABLE transactions ADD COLUMN schedule TEXT;
-
-COMMIT;
diff --git a/packages/desktop-client/public/data/migrations/1632571489012_remove_cache.js b/packages/desktop-client/public/data/migrations/1632571489012_remove_cache.js
deleted file mode 100644
index 2f3764c47dee15b631b96c3f8a95880ff9a101b9..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1632571489012_remove_cache.js
+++ /dev/null
@@ -1,135 +0,0 @@
-export default async function runMigration(db, uuid) {
-  function getValue(node) {
-    return node.expr != null ? node.expr : node.cachedValue;
-  }
-
-  db.execQuery(`
-CREATE TABLE zero_budget_months
-  (id TEXT PRIMARY KEY,
-   buffered INTEGER DEFAULT 0);
-
-CREATE TABLE zero_budgets
-  (id TEXT PRIMARY KEY,
-   month INTEGER,
-   category TEXT,
-   amount INTEGER DEFAULT 0,
-   carryover INTEGER DEFAULT 0);
-
-CREATE TABLE reflect_budgets
-  (id TEXT PRIMARY KEY,
-   month INTEGER,
-   category TEXT,
-   amount INTEGER DEFAULT 0,
-   carryover INTEGER DEFAULT 0);
-
-CREATE TABLE notes
-  (id TEXT PRIMARY KEY,
-   note TEXT);
-
-CREATE TABLE kvcache (key TEXT PRIMARY KEY, value TEXT);
-CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
-`);
-
-  // Migrate budget amounts and carryover
-  let budget = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!budget-%'`,
-    [],
-    true,
-  );
-  db.transaction(() => {
-    budget.forEach(monthBudget => {
-      let match = monthBudget.name.match(
-        /^(budget-report|budget)(\d+)!budget-(.+)$/,
-      );
-      if (match == null) {
-        console.log('Warning: invalid budget month name', monthBudget.name);
-        return;
-      }
-
-      let type = match[1];
-      let month = match[2].slice(0, 4) + '-' + match[2].slice(4);
-      let dbmonth = parseInt(match[2]);
-      let cat = match[3];
-
-      let amount = parseInt(getValue(monthBudget));
-      if (isNaN(amount)) {
-        amount = 0;
-      }
-
-      let sheetName = monthBudget.name.split('!')[0];
-      let carryover = db.runQuery(
-        'SELECT * FROM spreadsheet_cells WHERE name = ?',
-        [`${sheetName}!carryover-${cat}`],
-        true,
-      );
-
-      let table = type === 'budget-report' ? 'reflect_budgets' : 'zero_budgets';
-      db.runQuery(
-        `INSERT INTO ${table} (id, month, category, amount, carryover) VALUES (?, ?, ?, ?, ?)`,
-        [
-          `${month}-${cat}`,
-          dbmonth,
-          cat,
-          amount,
-          carryover.length > 0 && getValue(carryover[0]) === 'true' ? 1 : 0,
-        ],
-      );
-    });
-  });
-
-  // Migrate buffers
-  let buffers = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'budget%!buffered'`,
-    [],
-    true,
-  );
-  db.transaction(() => {
-    buffers.forEach(buffer => {
-      let match = buffer.name.match(/^budget(\d+)!buffered$/);
-      if (match) {
-        let month = match[1].slice(0, 4) + '-' + match[1].slice(4);
-        let amount = parseInt(getValue(buffer));
-        if (isNaN(amount)) {
-          amount = 0;
-        }
-
-        db.runQuery(
-          `INSERT INTO zero_budget_months (id, buffered) VALUES (?, ?)`,
-          [month, amount],
-        );
-      }
-    });
-  });
-
-  // Migrate notes
-  let notes = db.runQuery(
-    `SELECT * FROM spreadsheet_cells WHERE name LIKE 'notes!%'`,
-    [],
-    true,
-  );
-
-  let parseNote = str => {
-    try {
-      let value = JSON.parse(str);
-      return value && value !== '' ? value : null;
-    } catch (e) {
-      return null;
-    }
-  };
-
-  db.transaction(() => {
-    notes.forEach(note => {
-      let parsed = parseNote(getValue(note));
-      if (parsed) {
-        let [, id] = note.name.split('!');
-        db.runQuery(`INSERT INTO notes (id, note) VALUES (?, ?)`, [id, parsed]);
-      }
-    });
-  });
-
-  db.execQuery(`
-    DROP TABLE spreadsheet_cells;
-    ANALYZE;
-    VACUUM;
-  `);
-}
diff --git a/packages/desktop-client/public/data/migrations/1679728867040_rules_conditions.sql b/packages/desktop-client/public/data/migrations/1679728867040_rules_conditions.sql
deleted file mode 100644
index 9f12e68f9853fc7b529d7778224393e0a43b9a4f..0000000000000000000000000000000000000000
--- a/packages/desktop-client/public/data/migrations/1679728867040_rules_conditions.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-BEGIN TRANSACTION;
-
-ALTER TABLE rules ADD COLUMN conditions_op TEXT DEFAULT 'and';
-
-COMMIT;
diff --git a/packages/loot-core/bin/build-browser b/packages/loot-core/bin/build-browser
index e1da58008677067fecd84ab7164eac0163a043ad..bf7a0b1de7888e7beaa9bb7e53c9611b837205b9 100755
--- a/packages/loot-core/bin/build-browser
+++ b/packages/loot-core/bin/build-browser
@@ -4,7 +4,13 @@ cd `dirname "$0"`
 ROOT=`pwd -P`
 WEBPACK_ARGS=""
 
-"$ROOT"/copy-migrations
+DATA_DIR="$ROOT"/../../desktop-client/public/data
+mkdir -p "$DATA_DIR"
+"$ROOT"/copy-migrations "$DATA_DIR"
+
+cd "$DATA_DIR"
+find * -type f | sort > ../data-file-index.txt
+cd "$ROOT"
 
 OUTPUT_HASH="[hash]"
 if [ $NODE_ENV == 'development' ]; then
diff --git a/packages/loot-core/bin/copy-migrations b/packages/loot-core/bin/copy-migrations
index ebd0d00998431d3af2ba28c783be87601c1465ff..81eef9b31bcace7f348636e16a6e73f06667277b 100755
--- a/packages/loot-core/bin/copy-migrations
+++ b/packages/loot-core/bin/copy-migrations
@@ -1,14 +1,11 @@
 #!/bin/sh -e
 
+dest_dir=$(realpath "$1")
+
 ROOT=`dirname "$0"`
 cd "$ROOT"
 
-# Copy them to the browser version
-$(
-  cd ../../desktop-client/public;
-  rm -rf ./data;
-  mkdir ./data;
-  cp -r ../../loot-core/migrations ./data;
-  cp ../../loot-core/default-db.sqlite ./data;
-  cd data && find * -type f | sort > ../data-file-index.txt;
-)
+rm -rf "$dest_dir"/migrations
+mkdir -p "$dest_dir"/migrations
+cp ../migrations/* "$dest_dir"/migrations/
+cp ../default-db.sqlite "$dest_dir"
diff --git a/packages/loot-core/package.json b/packages/loot-core/package.json
index 611d9118f00a1f331a6ce32311bc688a2a248133..0522646f5fcc6d5471f8c04f9d46b8b48d1cf4f8 100644
--- a/packages/loot-core/package.json
+++ b/packages/loot-core/package.json
@@ -6,7 +6,7 @@
   "scripts": {
     "build:node": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.desktop.config.js",
     "watch:node": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.desktop.config.js --watch",
-    "build:api": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.api.config.js",
+    "build:api": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.api.config.js; ./bin/copy-migrations ../api",
     "build:browser": "cross-env NODE_ENV=production ./bin/build-browser",
     "watch:browser": "cross-env NODE_ENV=development ./bin/build-browser",
     "lint": "eslint .",
diff --git a/upcoming-release-notes/870.md b/upcoming-release-notes/870.md
new file mode 100644
index 0000000000000000000000000000000000000000..1647bb82e4c2e636a5b0848105d930acb3c7dfe8
--- /dev/null
+++ b/upcoming-release-notes/870.md
@@ -0,0 +1,6 @@
+---
+category: Maintenance
+authors: [j-f1]
+---
+
+Remove duplicate migration and default-db.sqlite files