diff --git a/lib/selectors/nav-selectors.js b/lib/selectors/nav-selectors.js
--- a/lib/selectors/nav-selectors.js
+++ b/lib/selectors/nav-selectors.js
@@ -14,7 +14,11 @@
 import type { CalendarFilter } from '../types/filter-types.js';
 import type { BaseNavInfo } from '../types/nav-types.js';
 import type { BaseAppState } from '../types/redux-types.js';
-import type { RawThreadInfo, ThreadInfo } from '../types/thread-types.js';
+import type {
+  RelativeMemberInfo,
+  RawThreadInfo,
+  ThreadInfo,
+} from '../types/thread-types';
 import type { UserInfo } from '../types/user-types.js';
 import { getConfig } from '../utils/config.js';
 import { values } from '../utils/objects.js';
@@ -72,12 +76,49 @@
   },
 );
 
-// Without allAtOnce, useThreadSearchIndex is very expensive. useENSNames would
-// trigger its recalculation for each ENS name as it streams in, but we would
-// prefer to trigger its recaculation just once for every update of the
-// underlying Redux data.
+// Without allAtOnce, useThreadSearchIndex and useUserSearchIndex are very
+// expensive. useENSNames would trigger their recalculation for each ENS name
+// as it streams in, but we would prefer to trigger their recaculation just
+// once for every update of the underlying Redux data.
 const useENSNamesOptions = { allAtOnce: true };
 
+function useUserSearchIndex(
+  userInfos: $ReadOnlyArray<UserInfo | RelativeMemberInfo>,
+): SearchIndex {
+  const membersWithENSNames = useENSNames(userInfos, useENSNamesOptions);
+
+  const memberMap = React.useMemo(() => {
+    const result = new Map<string, UserInfo | RelativeMemberInfo>();
+    for (const userInfo of membersWithENSNames) {
+      result.set(userInfo.id, userInfo);
+    }
+    return result;
+  }, [membersWithENSNames]);
+
+  return React.useMemo(() => {
+    const searchIndex = new SearchIndex();
+
+    for (const userInfo of userInfos) {
+      const searchTextArray = [];
+
+      const rawUsername = userInfo.username;
+      if (rawUsername) {
+        searchTextArray.push(rawUsername);
+      }
+
+      const resolvedUserInfo = memberMap.get(userInfo.id);
+      const resolvedUsername = resolvedUserInfo?.username;
+      if (resolvedUsername && resolvedUsername !== rawUsername) {
+        searchTextArray.push(resolvedUsername);
+      }
+
+      searchIndex.addEntry(userInfo.id, searchTextArray.join(' '));
+    }
+
+    return searchIndex;
+  }, [userInfos, memberMap]);
+}
+
 function useThreadSearchIndex(
   threadInfos: $ReadOnlyArray<RawThreadInfo | ThreadInfo>,
 ): SearchIndex {
@@ -167,6 +208,7 @@
 export {
   timeUntilCalendarRangeExpiration,
   currentCalendarQuery,
+  useUserSearchIndex,
   useThreadSearchIndex,
   useGlobalThreadSearchIndex,
 };
diff --git a/lib/shared/search-utils.js b/lib/shared/search-utils.js
--- a/lib/shared/search-utils.js
+++ b/lib/shared/search-utils.js
@@ -23,6 +23,7 @@
   ChatMessageInfoItem,
   MessageListData,
 } from '../selectors/chat-selectors.js';
+import { useUserSearchIndex } from '../selectors/nav-selectors.js';
 import { relationshipBlockedInEitherDirection } from '../shared/relationship-utils.js';
 import type { MessageInfo, RawMessageInfo } from '../types/message-types.js';
 import { userRelationshipStatus } from '../types/relationship-types.js';
@@ -89,7 +90,6 @@
 function usePotentialMemberItems({
   text,
   userInfos,
-  searchIndex,
   excludeUserIDs,
   includeServerSearchUsers,
   inputParentThreadInfo,
@@ -98,13 +98,14 @@
 }: {
   +text: string,
   +userInfos: { +[id: string]: AccountUserInfo },
-  +searchIndex: SearchIndex,
   +excludeUserIDs: $ReadOnlyArray<string>,
   +includeServerSearchUsers?: $ReadOnlyArray<GlobalAccountUserInfo>,
   +inputParentThreadInfo?: ?ThreadInfo,
   +inputCommunityThreadInfo?: ?ThreadInfo,
   +threadType?: ?ThreadType,
 }): UserListItem[] {
+  const searchIndex: SearchIndex = useUserSearchIndex(values(userInfos));
+
   const communityThreadInfo = React.useMemo(
     () =>
       inputCommunityThreadInfo && inputCommunityThreadInfo.id !== genesis.id
diff --git a/native/chat/compose-subchannel.react.js b/native/chat/compose-subchannel.react.js
--- a/native/chat/compose-subchannel.react.js
+++ b/native/chat/compose-subchannel.react.js
@@ -13,10 +13,7 @@
 } from 'lib/actions/thread-actions.js';
 import { useENSNames } from 'lib/hooks/ens-cache.js';
 import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import {
-  userInfoSelectorForPotentialMembers,
-  userSearchIndexForPotentialMembers,
-} from 'lib/selectors/user-selectors.js';
+import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import { usePotentialMemberItems } from 'lib/shared/search-utils.js';
 import { threadInFilterList, userIsMember } from 'lib/shared/thread-utils.js';
 import { type ThreadType, threadTypes } from 'lib/types/thread-types-enum.js';
@@ -195,7 +192,6 @@
   }, [newlyCreatedThreadInfo, pushNewThread]);
 
   const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers);
-  const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
   const { community } = parentThreadInfo;
   const communityThreadInfo = useSelector(state =>
     community ? threadInfoSelector(state)[community] : null,
@@ -203,7 +199,6 @@
   const userSearchResults = usePotentialMemberItems({
     text: usernameInputText,
     userInfos: otherUserInfos,
-    searchIndex: userSearchIndex,
     excludeUserIDs: userInfoInputIDs,
     inputParentThreadInfo: parentThreadInfo,
     inputCommunityThreadInfo: communityThreadInfo,
diff --git a/native/chat/message-list-container.react.js b/native/chat/message-list-container.react.js
--- a/native/chat/message-list-container.react.js
+++ b/native/chat/message-list-container.react.js
@@ -8,10 +8,7 @@
 
 import genesis from 'lib/facts/genesis.js';
 import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import {
-  userInfoSelectorForPotentialMembers,
-  userSearchIndexForPotentialMembers,
-} from 'lib/selectors/user-selectors.js';
+import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import {
   usePotentialMemberItems,
   useSearchUsers,
@@ -249,14 +246,12 @@
     >([]);
 
     const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers);
-    const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
 
     const serverSearchResults = useSearchUsers(usernameInputText);
 
     const userSearchResults = usePotentialMemberItems({
       text: usernameInputText,
       userInfos: otherUserInfos,
-      searchIndex: userSearchIndex,
       excludeUserIDs: userInfoInputArray.map(userInfo => userInfo.id),
       includeServerSearchUsers: serverSearchResults,
     });
diff --git a/native/chat/settings/add-users-modal.react.js b/native/chat/settings/add-users-modal.react.js
--- a/native/chat/settings/add-users-modal.react.js
+++ b/native/chat/settings/add-users-modal.react.js
@@ -10,10 +10,7 @@
 import { useENSNames } from 'lib/hooks/ens-cache.js';
 import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
 import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import {
-  userInfoSelectorForPotentialMembers,
-  userSearchIndexForPotentialMembers,
-} from 'lib/selectors/user-selectors.js';
+import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import { usePotentialMemberItems } from 'lib/shared/search-utils.js';
 import { threadActualMembers } from 'lib/shared/thread-utils.js';
 import type { ThreadInfo } from 'lib/types/thread-types.js';
@@ -165,7 +162,6 @@
   );
 
   const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers);
-  const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
   const { parentThreadID, community } = props.route.params.threadInfo;
   const parentThreadInfo = useSelector(state =>
     parentThreadID ? threadInfoSelector(state)[parentThreadID] : null,
@@ -176,7 +172,6 @@
   const userSearchResults = usePotentialMemberItems({
     text: usernameInputText,
     userInfos: otherUserInfos,
-    searchIndex: userSearchIndex,
     excludeUserIDs,
     inputParentThreadInfo: parentThreadInfo,
     inputCommunityThreadInfo: communityThreadInfo,
diff --git a/native/community-creation/community-creation-members.react.js b/native/community-creation/community-creation-members.react.js
--- a/native/community-creation/community-creation-members.react.js
+++ b/native/community-creation/community-creation-members.react.js
@@ -9,10 +9,7 @@
 } from 'lib/actions/thread-actions.js';
 import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js';
 import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import {
-  userInfoSelectorForPotentialMembers,
-  userSearchIndexForPotentialMembers,
-} from 'lib/selectors/user-selectors.js';
+import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import { usePotentialMemberItems } from 'lib/shared/search-utils.js';
 import type { LoadingStatus } from 'lib/types/loading-types.js';
 import { threadTypes } from 'lib/types/thread-types-enum.js';
@@ -68,7 +65,6 @@
   const { setOptions } = navigation;
 
   const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers);
-  const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
 
   const [usernameInputText, setUsernameInputText] = React.useState<string>('');
   const [selectedUsers, setSelectedUsers] = React.useState<
@@ -147,7 +143,6 @@
   const userSearchResults = usePotentialMemberItems({
     text: usernameInputText,
     userInfos: otherUserInfos,
-    searchIndex: userSearchIndex,
     excludeUserIDs: selectedUserIDs,
     threadType: announcement
       ? threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT
diff --git a/web/chat/chat-thread-composer.react.js b/web/chat/chat-thread-composer.react.js
--- a/web/chat/chat-thread-composer.react.js
+++ b/web/chat/chat-thread-composer.react.js
@@ -9,7 +9,6 @@
 import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
 import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js';
 import { useENSNames } from 'lib/hooks/ens-cache.js';
-import { userSearchIndexForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import {
   usePotentialMemberItems,
   useSearchUsers,
@@ -32,7 +31,6 @@
 import type { InputState } from '../input/input-state.js';
 import Alert from '../modals/alert.react.js';
 import { updateNavInfoActionType } from '../redux/action-types.js';
-import { useSelector } from '../redux/redux-utils.js';
 
 type Props = {
   +userInfoInputArray: $ReadOnlyArray<AccountUserInfo>,
@@ -51,7 +49,6 @@
   const [usernameInputText, setUsernameInputText] = React.useState('');
 
   const dispatch = useDispatch();
-  const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
 
   const userInfoInputIDs = React.useMemo(
     () => userInfoInputArray.map(userInfo => userInfo.id),
@@ -63,7 +60,6 @@
   const userListItems = usePotentialMemberItems({
     text: usernameInputText,
     userInfos: otherUserInfos,
-    searchIndex: userSearchIndex,
     excludeUserIDs: userInfoInputIDs,
     includeServerSearchUsers: serverSearchResults,
   });
diff --git a/web/modals/threads/members/add-members-modal.react.js b/web/modals/threads/members/add-members-modal.react.js
--- a/web/modals/threads/members/add-members-modal.react.js
+++ b/web/modals/threads/members/add-members-modal.react.js
@@ -8,10 +8,7 @@
 } from 'lib/actions/thread-actions.js';
 import { useENSNames } from 'lib/hooks/ens-cache.js';
 import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
-import {
-  userSearchIndexForPotentialMembers,
-  userInfoSelectorForPotentialMembers,
-} from 'lib/selectors/user-selectors.js';
+import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js';
 import { usePotentialMemberItems } from 'lib/shared/search-utils.js';
 import { threadActualMembers } from 'lib/shared/thread-utils.js';
 import { useDispatchActionPromise } from 'lib/utils/action-utils.js';
@@ -45,7 +42,6 @@
     community ? threadInfoSelector(state)[community] : null,
   );
   const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers);
-  const userSearchIndex = useSelector(userSearchIndexForPotentialMembers);
   const excludeUserIDs = React.useMemo(
     () =>
       threadActualMembers(threadInfo.members).concat(
@@ -57,7 +53,6 @@
   const userSearchResults = usePotentialMemberItems({
     text: searchText,
     userInfos: otherUserInfos,
-    searchIndex: userSearchIndex,
     excludeUserIDs,
     inputParentThreadInfo: parentThreadInfo,
     inputCommunityThreadInfo: communityThreadInfo,