Cara, muito legal o conteúdo. Esse é um debate muito profundo e bem legal, geralmente temos contato com esse tipo de coisa só trabalhando em grandes plataformas ou dando a cara a tapa pra fazer o nosso próprio, achei muito massa. Queria só chamar sua atenção pra alguns detalhes, que não diminuem em nada o que você fez, mas que se forem melhorados você conseguirá resolver o seu problema com ainda mais assertividade:

  1. Dar um limit: 20 no número de usuários não vai deixar sua pesquisa no banco mais perfomática.

Limitar a quantidade de resultados é a última coisa feita na execução de uma query no banco, vê aqui. Isso significa que o esforço pra procurar pelos itens que atendem ao where é basicamente o mesmo, a diferença está no tamanho do retorno (e quanto ele ocupa na memória) e o tempo que o banco leva pra serializar tudo isso no formato json e te devolver. Ajuda? Sim. Mas pro banco tanto faz.

  1. username: {[Op.like]: %${username_to_search}%} essa linha aqui.

Esse provavelmente é o principal ofensor da sua performance. Acho que já deve saber disso, mas essas pesquisas com like custam muito caro e seria interessante que você fizesse um índicie pra essa coluna pra fazer pesquisas com full text search. Dá uma olhada nesse video do Akita, que ele passa pelo assunto de forrma bem didática. Pra poucos usuários funciona bem, mas como sua intenção é escalar logo será um problema ter que checar todas as linhas procurando o que tiver dentro desses %%

  1. Dado que seu único parâmetro de busca relevante é o username e você retorna resultados limitados a 20, você não consegue garantir que os melhores resultados venham nas 20 primeiras posições.

Já que o banco filtra apenas por usernames, seu algoritmo é capaz de classificar os usuários como mais ou menos relevantes em lotes de 20 em 20 (número do limit). Se o usuário que você quiser exibir como sendo o mais relevante possível retornar na 24° posição da busca por usuários, ele não será exibido. O problema não é o tamanho do limit, mas sim, que o único critério que o banco tem pra retornar os usuários é o usernames sem um order_by claro. Pra melhorar isso de forma simples, talvez você pudesse calcular com um número maior de usuários e devolver um resultado com um número menor, isso adia o problema mas ajuda. (Ex: calcular a relevância de 1000 usuários e devolver 20).

Novamente, esses pontos são só algumas melhorias que eu achei interessantes PONTUAR como temas de estudo e aprofundamento. O que você fez já é muito legal e um excelente ponto de partida pra aprender sobre temas que nem todo mundo tem disposição nem de tentar fazer. Então continue firme, adote o que você achar que te acrescenta ou então mas insisto que é interessante dar uma olhadinha.

Valeu e parabéns!!