diff --git a/keyserver/src/creators/update-creator.js b/keyserver/src/creators/update-creator.js
--- a/keyserver/src/creators/update-creator.js
+++ b/keyserver/src/creators/update-creator.js
@@ -8,6 +8,7 @@
   keyForUpdateInfo,
   rawUpdateInfoFromUpdateData,
 } from 'lib/shared/update-utils.js';
+import { updateSpecs } from 'lib/shared/updates/update-specs.js';
 import {
   type RawEntryInfos,
   type FetchEntryInfosBase,
@@ -190,35 +191,6 @@
   const earliestTime: Map<string, number> = new Map();
   for (let i = 0; i < filteredUpdateDatas.length; i++) {
     const updateData = filteredUpdateDatas[i];
-    let content;
-    if (updateData.type === updateTypes.DELETE_ACCOUNT) {
-      content = JSON.stringify({ deletedUserID: updateData.deletedUserID });
-    } else if (updateData.type === updateTypes.UPDATE_THREAD) {
-      content = JSON.stringify({ threadID: updateData.threadID });
-    } else if (updateData.type === updateTypes.UPDATE_THREAD_READ_STATUS) {
-      const { threadID, unread } = updateData;
-      content = JSON.stringify({ threadID, unread });
-    } else if (
-      updateData.type === updateTypes.DELETE_THREAD ||
-      updateData.type === updateTypes.JOIN_THREAD
-    ) {
-      const { threadID } = updateData;
-      content = JSON.stringify({ threadID });
-    } else if (updateData.type === updateTypes.BAD_DEVICE_TOKEN) {
-      const { deviceToken } = updateData;
-      content = JSON.stringify({ deviceToken });
-    } else if (updateData.type === updateTypes.UPDATE_ENTRY) {
-      const { entryID } = updateData;
-      content = JSON.stringify({ entryID });
-    } else if (updateData.type === updateTypes.UPDATE_CURRENT_USER) {
-      // user column contains all the info we need to construct the UpdateInfo
-      content = null;
-    } else if (updateData.type === updateTypes.UPDATE_USER) {
-      const { updatedUserID } = updateData;
-      content = JSON.stringify({ updatedUserID });
-    } else {
-      invariant(false, `unrecognized updateType ${updateData.type}`);
-    }
 
     const target = getTargetFromUpdateData(updateData);
     const rawUpdateInfo = rawUpdateInfoFromUpdateData(updateData, ids[i]);
@@ -251,6 +223,9 @@
       continue;
     }
 
+    const content =
+      updateSpecs[updateData.type].updateContentForServerDB(updateData);
+
     const key = keyForUpdateData(updateData);
     if (key) {
       const conditionKey = `${updateData.userID}|${key}`;
diff --git a/lib/shared/updates/bad-device-token-spec.js b/lib/shared/updates/bad-device-token-spec.js
--- a/lib/shared/updates/bad-device-token-spec.js
+++ b/lib/shared/updates/bad-device-token-spec.js
@@ -4,12 +4,14 @@
 import { updateTypes } from '../../types/update-types-enum.js';
 import type {
   BadDeviceTokenRawUpdateInfo,
+  BadDeviceTokenUpdateData,
   BadDeviceTokenUpdateInfo,
 } from '../../types/update-types.js';
 
 export const badDeviceTokenSpec: UpdateSpec<
   BadDeviceTokenUpdateInfo,
   BadDeviceTokenRawUpdateInfo,
+  BadDeviceTokenUpdateData,
 > = Object.freeze({
   rawUpdateInfoFromRow(row: Object) {
     const { deviceToken } = JSON.parse(row.content);
@@ -20,4 +22,8 @@
       deviceToken,
     };
   },
+  updateContentForServerDB(data: BadDeviceTokenUpdateData) {
+    const { deviceToken } = data;
+    return JSON.stringify({ deviceToken });
+  },
 });
diff --git a/lib/shared/updates/delete-account-spec.js b/lib/shared/updates/delete-account-spec.js
--- a/lib/shared/updates/delete-account-spec.js
+++ b/lib/shared/updates/delete-account-spec.js
@@ -5,6 +5,7 @@
 import { updateTypes } from '../../types/update-types-enum.js';
 import type {
   AccountDeletionRawUpdateInfo,
+  AccountDeletionUpdateData,
   AccountDeletionUpdateInfo,
 } from '../../types/update-types.js';
 import type { UserInfos } from '../../types/user-types.js';
@@ -12,6 +13,7 @@
 export const deleteAccountSpec: UpdateSpec<
   AccountDeletionUpdateInfo,
   AccountDeletionRawUpdateInfo,
+  AccountDeletionUpdateData,
 > = Object.freeze({
   generateOpsForThreadUpdates(
     storeThreadInfos: RawThreadInfos,
@@ -56,4 +58,7 @@
       deletedUserID: content.deletedUserID,
     };
   },
+  updateContentForServerDB(data: AccountDeletionUpdateData) {
+    return JSON.stringify({ deletedUserID: data.deletedUserID });
+  },
 });
diff --git a/lib/shared/updates/delete-thread-spec.js b/lib/shared/updates/delete-thread-spec.js
--- a/lib/shared/updates/delete-thread-spec.js
+++ b/lib/shared/updates/delete-thread-spec.js
@@ -5,12 +5,14 @@
 import { updateTypes } from '../../types/update-types-enum.js';
 import type {
   ThreadDeletionRawUpdateInfo,
+  ThreadDeletionUpdateData,
   ThreadDeletionUpdateInfo,
 } from '../../types/update-types.js';
 
 export const deleteThreadSpec: UpdateSpec<
   ThreadDeletionUpdateInfo,
   ThreadDeletionRawUpdateInfo,
+  ThreadDeletionUpdateData,
 > = Object.freeze({
   generateOpsForThreadUpdates(
     storeThreadInfos: RawThreadInfos,
@@ -46,4 +48,8 @@
       threadID,
     };
   },
+  updateContentForServerDB(data: ThreadDeletionUpdateData) {
+    const { threadID } = data;
+    return JSON.stringify({ threadID });
+  },
 });
diff --git a/lib/shared/updates/join-thread-spec.js b/lib/shared/updates/join-thread-spec.js
--- a/lib/shared/updates/join-thread-spec.js
+++ b/lib/shared/updates/join-thread-spec.js
@@ -13,6 +13,7 @@
 import type {
   ThreadJoinUpdateInfo,
   ThreadJoinRawUpdateInfo,
+  ThreadJoinUpdateData,
 } from '../../types/update-types.js';
 import { combineTruncationStatuses } from '../message-utils.js';
 import { threadInFilterList } from '../thread-utils.js';
@@ -20,6 +21,7 @@
 export const joinThreadSpec: UpdateSpec<
   ThreadJoinUpdateInfo,
   ThreadJoinRawUpdateInfo,
+  ThreadJoinUpdateData,
 > = Object.freeze({
   generateOpsForThreadUpdates(
     storeThreadInfos: RawThreadInfos,
@@ -96,4 +98,8 @@
       threadID,
     };
   },
+  updateContentForServerDB(data: ThreadJoinUpdateData) {
+    const { threadID } = data;
+    return JSON.stringify({ threadID });
+  },
 });
diff --git a/lib/shared/updates/update-current-user-spec.js b/lib/shared/updates/update-current-user-spec.js
--- a/lib/shared/updates/update-current-user-spec.js
+++ b/lib/shared/updates/update-current-user-spec.js
@@ -7,12 +7,14 @@
 import type {
   CurrentUserUpdateInfo,
   CurrentUserRawUpdateInfo,
+  CurrentUserUpdateData,
 } from '../../types/update-types.js';
 import type { CurrentUserInfo } from '../../types/user-types.js';
 
 export const updateCurrentUserSpec: UpdateSpec<
   CurrentUserUpdateInfo,
   CurrentUserRawUpdateInfo,
+  CurrentUserUpdateData,
 > = Object.freeze({
   reduceCurrentUser(state: ?CurrentUserInfo, update: CurrentUserUpdateInfo) {
     if (!_isEqual(update.currentUserInfo)(state)) {
@@ -27,4 +29,8 @@
       time: row.time,
     };
   },
+  updateContentForServerDB() {
+    // user column contains all the info we need to construct the UpdateInfo
+    return null;
+  },
 });
diff --git a/lib/shared/updates/update-entry-spec.js b/lib/shared/updates/update-entry-spec.js
--- a/lib/shared/updates/update-entry-spec.js
+++ b/lib/shared/updates/update-entry-spec.js
@@ -6,30 +6,38 @@
 import type {
   EntryUpdateInfo,
   EntryRawUpdateInfo,
+  EntryUpdateData,
 } from '../../types/update-types.js';
 
-export const updateEntrySpec: UpdateSpec<EntryUpdateInfo, EntryRawUpdateInfo> =
-  Object.freeze({
-    mergeEntryInfos(
-      entryIDs: Set<string>,
-      mergedEntryInfos: Array<RawEntryInfo>,
-      update: EntryUpdateInfo,
-    ) {
-      const { entryInfo } = update;
-      const entryID = entryInfo.id;
-      if (!entryID || entryIDs.has(entryID)) {
-        return;
-      }
-      mergedEntryInfos.push(entryInfo);
-      entryIDs.add(entryID);
-    },
-    rawUpdateInfoFromRow(row: Object) {
-      const { entryID } = JSON.parse(row.content);
-      return {
-        type: updateTypes.UPDATE_ENTRY,
-        id: row.id.toString(),
-        time: row.time,
-        entryID,
-      };
-    },
-  });
+export const updateEntrySpec: UpdateSpec<
+  EntryUpdateInfo,
+  EntryRawUpdateInfo,
+  EntryUpdateData,
+> = Object.freeze({
+  mergeEntryInfos(
+    entryIDs: Set<string>,
+    mergedEntryInfos: Array<RawEntryInfo>,
+    update: EntryUpdateInfo,
+  ) {
+    const { entryInfo } = update;
+    const entryID = entryInfo.id;
+    if (!entryID || entryIDs.has(entryID)) {
+      return;
+    }
+    mergedEntryInfos.push(entryInfo);
+    entryIDs.add(entryID);
+  },
+  rawUpdateInfoFromRow(row: Object) {
+    const { entryID } = JSON.parse(row.content);
+    return {
+      type: updateTypes.UPDATE_ENTRY,
+      id: row.id.toString(),
+      time: row.time,
+      entryID,
+    };
+  },
+  updateContentForServerDB(data: EntryUpdateData) {
+    const { entryID } = data;
+    return JSON.stringify({ entryID });
+  },
+});
diff --git a/lib/shared/updates/update-spec.js b/lib/shared/updates/update-spec.js
--- a/lib/shared/updates/update-spec.js
+++ b/lib/shared/updates/update-spec.js
@@ -10,10 +10,15 @@
 import type {
   ClientUpdateInfo,
   RawUpdateInfo,
+  UpdateData,
 } from '../../types/update-types.js';
 import type { CurrentUserInfo, UserInfos } from '../../types/user-types.js';
 
-export type UpdateSpec<UpdateInfo: ClientUpdateInfo, RawInfo: RawUpdateInfo> = {
+export type UpdateSpec<
+  UpdateInfo: ClientUpdateInfo,
+  RawInfo: RawUpdateInfo,
+  Data: UpdateData,
+> = {
   +generateOpsForThreadUpdates?: (
     storeThreadInfos: RawThreadInfos,
     update: UpdateInfo,
@@ -40,4 +45,5 @@
     update: UpdateInfo,
   ) => void,
   +rawUpdateInfoFromRow: (row: Object) => RawInfo,
+  +updateContentForServerDB: (data: Data) => ?string,
 };
diff --git a/lib/shared/updates/update-specs.js b/lib/shared/updates/update-specs.js
--- a/lib/shared/updates/update-specs.js
+++ b/lib/shared/updates/update-specs.js
@@ -13,7 +13,7 @@
 import { updateTypes, type UpdateType } from '../../types/update-types-enum.js';
 
 export const updateSpecs: {
-  +[UpdateType]: UpdateSpec<*, *>,
+  +[UpdateType]: UpdateSpec<*, *, *>,
 } = Object.freeze({
   [updateTypes.DELETE_ACCOUNT]: deleteAccountSpec,
   [updateTypes.UPDATE_THREAD]: updateThreadSpec,
diff --git a/lib/shared/updates/update-thread-read-status-spec.js b/lib/shared/updates/update-thread-read-status-spec.js
--- a/lib/shared/updates/update-thread-read-status-spec.js
+++ b/lib/shared/updates/update-thread-read-status-spec.js
@@ -9,11 +9,13 @@
 import type {
   ThreadReadStatusUpdateInfo,
   ThreadReadStatusRawUpdateInfo,
+  ThreadReadStatusUpdateData,
 } from '../../types/update-types.js';
 
 export const updateThreadReadStatusSpec: UpdateSpec<
   ThreadReadStatusUpdateInfo,
   ThreadReadStatusRawUpdateInfo,
+  ThreadReadStatusUpdateData,
 > = Object.freeze({
   generateOpsForThreadUpdates(
     storeThreadInfos: RawThreadInfos,
@@ -53,4 +55,8 @@
       unread,
     };
   },
+  updateContentForServerDB(data: ThreadReadStatusUpdateData) {
+    const { threadID, unread } = data;
+    return JSON.stringify({ threadID, unread });
+  },
 });
diff --git a/lib/shared/updates/update-thread-spec.js b/lib/shared/updates/update-thread-spec.js
--- a/lib/shared/updates/update-thread-spec.js
+++ b/lib/shared/updates/update-thread-spec.js
@@ -8,12 +8,14 @@
 import type {
   ThreadUpdateInfo,
   ThreadRawUpdateInfo,
+  ThreadUpdateData,
 } from '../../types/update-types.js';
 import { threadInFilterList } from '../thread-utils.js';
 
 export const updateThreadSpec: UpdateSpec<
   ThreadUpdateInfo,
   ThreadRawUpdateInfo,
+  ThreadUpdateData,
 > = Object.freeze({
   generateOpsForThreadUpdates(
     storeThreadInfos: RawThreadInfos,
@@ -55,4 +57,7 @@
       threadID,
     };
   },
+  updateContentForServerDB(data: ThreadUpdateData) {
+    return JSON.stringify({ threadID: data.threadID });
+  },
 });
diff --git a/lib/shared/updates/update-user-spec.js b/lib/shared/updates/update-user-spec.js
--- a/lib/shared/updates/update-user-spec.js
+++ b/lib/shared/updates/update-user-spec.js
@@ -5,17 +5,25 @@
 import type {
   UserUpdateInfo,
   UserRawUpdateInfo,
+  UserUpdateData,
 } from '../../types/update-types.js';
 
-export const updateUserSpec: UpdateSpec<UserUpdateInfo, UserRawUpdateInfo> =
-  Object.freeze({
-    rawUpdateInfoFromRow(row: Object) {
-      const content = JSON.parse(row.content);
-      return {
-        type: updateTypes.UPDATE_USER,
-        id: row.id.toString(),
-        time: row.time,
-        updatedUserID: content.updatedUserID,
-      };
-    },
-  });
+export const updateUserSpec: UpdateSpec<
+  UserUpdateInfo,
+  UserRawUpdateInfo,
+  UserUpdateData,
+> = Object.freeze({
+  rawUpdateInfoFromRow(row: Object) {
+    const content = JSON.parse(row.content);
+    return {
+      type: updateTypes.UPDATE_USER,
+      id: row.id.toString(),
+      time: row.time,
+      updatedUserID: content.updatedUserID,
+    };
+  },
+  updateContentForServerDB(data: UserUpdateData) {
+    const { updatedUserID } = data;
+    return JSON.stringify({ updatedUserID });
+  },
+});
diff --git a/lib/types/update-types.js b/lib/types/update-types.js
--- a/lib/types/update-types.js
+++ b/lib/types/update-types.js
@@ -53,51 +53,51 @@
   +userID: string,
   +time: number,
 };
-type AccountDeletionUpdateData = {
+export type AccountDeletionUpdateData = {
   ...SharedUpdateData,
   ...AccountDeletionData,
   +type: 0,
 };
-type ThreadUpdateData = {
+export type ThreadUpdateData = {
   ...SharedUpdateData,
   ...ThreadData,
   +type: 1,
   +targetSession?: string,
 };
-type ThreadReadStatusUpdateData = {
+export type ThreadReadStatusUpdateData = {
   ...SharedUpdateData,
   ...ThreadReadStatusData,
   +type: 2,
 };
-type ThreadDeletionUpdateData = {
+export type ThreadDeletionUpdateData = {
   ...SharedUpdateData,
   ...ThreadDeletionData,
   +type: 3,
 };
-type ThreadJoinUpdateData = {
+export type ThreadJoinUpdateData = {
   ...SharedUpdateData,
   ...ThreadJoinData,
   +type: 4,
   +targetSession?: string,
 };
-type BadDeviceTokenUpdateData = {
+export type BadDeviceTokenUpdateData = {
   ...SharedUpdateData,
   ...BadDeviceTokenData,
   +type: 5,
   +targetCookie: string,
 };
-type EntryUpdateData = {
+export type EntryUpdateData = {
   ...SharedUpdateData,
   ...EntryData,
   +type: 6,
   +targetSession: string,
 };
-type CurrentUserUpdateData = {
+export type CurrentUserUpdateData = {
   ...SharedUpdateData,
   ...CurrentUserData,
   +type: 7,
 };
-type UserUpdateData = {
+export type UserUpdateData = {
   ...SharedUpdateData,
   ...UserData,
   +type: 8,