SearchParams no Next.js 15: Como usar parâmetros da URL

Uma necessidade comum em muitas aplicações web, é poder construir o conteúdo de uma página dinamicamente através de parâmetros passados via url, esses parâmetros acabam definindo um estado para a aplicação e possibilitando compartilhar a url naquele estado específico. Em cada linguagem de programação/framework existe uma forma distinta de manipular esses parâmetros, e no Next.js isso é feito através da propriedade searchParams que é passada para todas as páginas e layouts, e através do hook useSearchParams.
Neste artigo vou demonstrar um pouco como utilizar essas duas funcionalidades e dar alguns exemplos de como podemos manipular os parâmetros da URL em projeto Next.js, tanto na parte do servidor quanto do cliente. Todos os exemplos serão feitos considerando o uso do App Router.

Preciso mesmo usar as apis de searchParams do Next.js?
Apesar de ser possível manipular os parâmetros de url, utilizando a api padrão do Javascript para manipulação de parâmetros em um projeto Next.js, isso não é recomendado, pois manipular diretamente os parâmetros de URL com JavaScript em um projeto Next.js pode trazer alguns problemas em termos de consistência e compatibilidade com o roteamento do framework, gerando comportamentos inesperados na aplicação.
Possíveis Problemas ao Manipular Parâmetros de URL Diretamente
- Inconsistência com o Roteamento do Next.js: Next.js utiliza o hook
useRouter
para gerenciar o estado de navegação. Alterar a URL diretamente com JavaScript pode causar inconsistências, pois o estado de navegação do Next.js não será atualizado automaticamente. Isso pode fazer com que a aplicação perca o controle sobre o histórico de navegação, o que é especialmente problemático em aplicações que dependem de redirecionamentos ou navegação condicional. - Falhas em Recursos de Renderização: Se você manipula parâmetros diretamente sem o
useRouter
, alguns recursos específicos do framework, como renderização condicional de páginas ou recuperação de dados baseada em parâmetros, podem não responder corretamente, já que esses dados não foram atualizados pelo roteamento do Next.js. Esse problema ocorre especialmente em rotas com pré-renderização estática ou server-side rendering, onde os parâmetros não estão sincronizados. - Comportamento Inesperado com o Histórico de Navegação: Quando você usa
window.history.pushState
oureplaceState
para manipular URLs, essas mudanças não são detectadas pelo Next.js. Portanto, ao navegar para outra página e retornar, o estado anterior não será mantido, o que pode confundir os usuários. - Problemas de Performance e Consistência em Atualizações: Dependendo de como os parâmetros de URL são manipulados, pode haver problemas de performance, como atualizações não otimizadas de componentes. O
useRouter
cuida de otimizações de atualização de URL e mantém os componentes sincronizados com o estado da aplicação, ao contrário de uma manipulação direta com JavaScript.
Exemplo de manipulação errada
O código abaixo demonstra um componente que faz manipulações nos parâmetros de URL direto usando as apis padrão do Javascript. Dessa forma, caso o usuário utilize o botão voltar do browser, o estado da aplicação fica errado, uma vez que o Next.js não atualizou o estado interno da navegação.
const Page = () => {
const [filter, setFilter] = useState('all');
// Manipulação direta do URL quando o filtro é alterado
const updateURL = (newFilter: string) => {
const url = new URL(window.location.href);
url.searchParams.set('filter', newFilter);
window.history.pushState({}, '', url);
setFilter(newFilter); // Atualiza o estado local
};
useEffect(() => {
// Exemplo: Acessa o valor inicial do filtro da URL
const params = new URLSearchParams(window.location.search);
const initialFilter = params.get('filter') || 'all';
setFilter(initialFilter);
}, []);
return (
<div>
<h1>Produtos</h1>
<select onChange={(e) => updateURL(e.target.value)} value={filter}>
<option value="all">Todos</option>
<option value="eletronicos">Eletrônicos</option>
<option value="livros">Livros</option>
</select>
<p>Filtro atual: {filter}</p>
</div>
);
};
O vídeo abaixo demonstra o resultado do código anterior e o problema causado:
Manipulando searchParams do Next.js em componentes client-side
Para evitar os problemas descritos acima, você deve utilizar as apis internas do próprio Next.js para manipular os parâmetros da URL. A primeira forma de manipular os parâmetros de URL com Next.js é fazendo direto na parte client-side da aplicação. Para isso, utilizamos o hook useSearchParams, que nada mais é que uma instância somente leitura da interface URLSearchParams, que é controlada internamente pelo próprio framework para garantir que ao ler os parâmetros, eles estarão sempre sincronizados com o estado da aplicação.
Utilizando o exemplo acima, vamos alterar a leitura dos parâmetros para o seguinte modelo:
const params = useSearchParams();
const [filter, setFilter] = useState('all');
useEffect(() => {
const initialFilter = params.get('filter') || 'all';
setFilter(initialFilter);
}, [params]);
Como modificar os searchParams com Next.js?
Como mencionando anteriormente, o hook useSearchParams
retorna um objeto somente leitura, então como fazemos para alterar os parâmetros da URL pela nossa aplicação Next.js client-side? Para isso, vamos utilizar a api de navegação do Next.js através do hook useRouter
que permite alterar as rotas em um componente client-side.
Para modificar os parâmetros da URL e adicionar uma nova entrada no histórico de navegação do usuário, como numa situação de um filtro em uma loja virtual, semelhante ao exemplo anterior, vamos utilizar o método push
.
Utilizando nosso exemplo do filtro, vamos alterar o código que modifica os parâmetros para o código abaixo:
const router = useRouter();
const pathname = usePathname();
const params = useSearchParams();
const [filter, setFilter] = useState('all');
const updateFilter = (newFilter: string) => {
const searchParams = new URLSearchParams(params);
searchParams.set('filter', newFilter);
router.push(`${pathname}?${searchParams.toString()}`);
};
No código acima, além do useRouter
, também utilizamos o hook usePathname
, que permite ler o path da URL. Perceba que primeiro instanciamos um novo objeto URLSearchParams
a partir do searchParams
atual obtido com o useSearchParams
. Isso é necessário para evitar que sejam perdidos outros parâmetros da URL além do filter.
Após a criação de um novo objeto URLSearchParams
e alteração do parâmetro filter nesse novo objeto, é feita uma navegação para a mesma url, com os parâmetros alterados router.push(${pathname}?${searchParams.toString()})
como tudo foi feito utilizando as apis do próprio Next.js, esse fluxo irá automaticamente disparar o useEffect
configurado no bloco anterior, alterando o estado da aplicação.
Abaixo a demonstração do resultado após as alterações feitas. Podemos ver o comportamento correto ao utilizar modificar o filtro na aplicação, ao utilizar o botão voltar, e ao carregar direto com o filtro na url.
Um problema que podemos notar no vídeo acima, é que quando acessamos a aplicação direto com a url já filtrada o valor do filtro é exibido de uma forma e depois muda. Isso acontece devido ao fato de estarmos processando o parâmetro da url apenas no lado do cliente.
Dessa maneira, o Next.js pré-renderiza o componente no backend, sem saber o estado do filtro, e após a hidratação dos componentes, o estado interno do componente muda, e passa a considerar o filtro na url.
Para resolver esse problema, podemos utilizar o filtro no componente server-side, e assim o Next.js já consegue enviar o html da página considerando o estado da url, conforme vamos ver a seguir.
Manipulando searchParams do Next.js em componentes server-side
Por mais que com o uso dos exemplos anteriores já seja possível cobrir todos os casos de manipulação dos parâmetros da url da aplicação, é interessante conseguirmos fazer isso também no lado do servidor, para conseguirmos otimizar nossa aplicação e evitar processamento desnecessário no lado cliente.
No nosso exemplo do filtro, se nossa aplicação consumir alguma outra api interna, e enviar esse filtro como parâmetro da chamada para essa api, é interessante podermos obter esses valores no lado do servidor, para conseguirmos comunicar com esse serviço interno direto no backend.
Vantagens de manipular os searchParams do Next.js no backend
SEO e Renderização Otimizada:
- Ler e processar os
searchParams
no servidor permite que o Next.js pré-renderize a página com base nos parâmetros de URL, melhorando a performance e a experiência do usuário final. A página carregada já é otimizada e configurada para o estado desejado, reduzindo a necessidade de renderizações adicionais no cliente. - Isso também melhora o SEO, pois o conteúdo é servido de forma estática para os bots de busca, já estruturado de acordo com os parâmetros específicos. Essa abordagem permite otimizar o conteúdo e os metadados com base nos parâmetros, ajudando a página a ser indexada de forma mais eficaz.
Segurança e Validação dos Parâmetros:
- No lado do servidor, você pode validar e sanitizar
searchParams
antes que eles cheguem ao cliente, garantindo que apenas dados seguros e corretos sejam enviados para renderização. Isso é especialmente importante para proteger contra injeções maliciosas e outras vulnerabilidades de segurança. - Parâmetros podem ser modificados e validados de forma centralizada, garantindo consistência e integridade em toda a aplicação, sem depender da validação no cliente.
Performance:
- Quando você manipula
searchParams
no servidor, é possível aplicar renderização condicional para entregar apenas o conteúdo necessário para cada combinação de parâmetros, economizando recursos e tempo de resposta. Por exemplo, ao usarsearchParams
para filtros de produtos, o Next.js pode pré-filtrar e enviar apenas os produtos relevantes ao cliente. - Além disso, isso permite que certas partes da aplicação usem Server-Side Rendering (SSR) ou Incremental Static Regeneration (ISR) para revalidar ou atualizar dados automaticamente.
- Ao ler e processar os parâmetros diretamente no servidor, você evita a necessidade de fazer requisições adicionais ao backend depois que a página é carregada. A aplicação pode, por exemplo, carregar uma lista filtrada de dados ou conteúdo baseado nos parâmetros diretamente no momento da renderização da página.
Como manipular o searchParams do Next.js no backend?
Além do hook useSearchParams
o App Router disponibiliza em todas as páginas uma propriedade chamada searchParams, essa propriedade pode ser acessada tanto em componentes client-side, quanto em componentes server-side.
A partir da versão 15 do Next.js, essa propriedade passou a ser uma Promise, portanto, para acessa-la, precisamos utilizar async/await
ou então a api use do React.
Para demonstrar o uso do searchParams
vamos evoluir o exemplo anterior para buscar e renderizar os produtos de acordo com o filtro.
O primeiro ajuste que vamos fazer é extrair a lógica do filtro para um componente a parte, conforme o código abaixo:
function FilterComp({ filter }: FilterProps) {
const params = useSearchParams();
const router = useRouter();
const pathname = usePathname();
const updateFilter = (newFilter: string) => {
const searchParams = new URLSearchParams(params);
searchParams.set('filter', newFilter);
router.push(`${pathname}?${searchParams.toString()}`);
};
return (
<>
<select onChange={(e) => updateFilter(e.target.value)} value={filter}>
<option value="all">Todos</option>
<option value="eletronicos">Eletrônicos</option>
<option value="livros">Livros</option>
</select>
<p>Filtro atual: {filter}</p>
</>
);
};
Precisamos fazer isso por conta uso dos react hooks, como usePathname
, useState
etc … esses hooks só estão acessíveis em componentes client-side, e como queremos manter a nossa página como um componente server-side, extraímos essa parte em um componente separado.
Perceba que agora não é mais necessário manter o useEffect
que faz a inicialização do filtro a partir do useSearchParams
, e nem um estado de filter
interno. Os parâmetros são lidos pela página na prop searchParams
e passados para o componente de filtro via parâmetro.
Além da extração do filtro, criamos um componente ProductGrid
que é basicamente uma lista de produtos a serem exibidos.
const ProductGrid: React.FC<ProductGridProps> = ({ products }) => {
return (
<div>
<ul>
{products.map((product, index) => (
<li key={index}>
<strong>Category:</strong> {product.cat} - <strong>Name:</strong> {product.name}
</li>
))}
</ul>
</div>
);
};
Também criamos um mock de um service para carregar esses produtos a partir de um json estático:
import products from './products.json';
export function loadProducts(filter: string = 'all') {
if (filter === 'all') {
return products;
}
return products.filter((product) => product.cat === filter);
}
E juntamos todos esses componentes no page.tsx
conforme abaixo:
import { use } from 'react';
import FilterComp from './Filter';
import { loadProducts } from './product-service';
import ProductGrid from './ProductGrid';
type PageProps = {
searchParams: Promise<{
filter: string;
}>;
};
export default function Page(props: PageProps) {
const params = use(props.searchParams);
const products = loadProducts(params.filter);
return (
<div>
<h1>Produtos</h1>
<FilterComp initialFilter={params.filter}/>
<ProductGrid products={products} />
</div>
);
}
Com isso conseguimos ter a renderização do estado inicial do filtro, e o grid de produtos já no backend, trazendo o html pronto para exibição no browser, antes mesmo do react hidratar os componentes.
A sequência do vídeo de demonstração deixa claro o cenário final:
Agora podemos ver no vídeo que a experiência fica visivelmente melhor, com a página sempre renderizando já com o seu conteúdo pronto.
Conclusão
Manipular os searchParams
em um projeto Next.js é simples, desde que feito da forma correta, com as apis do próprio framework.
Devemos evitar ao máximo utilizar as apis nativas do browser para manipular elementos da navegação, e sempre que possível, estruturar nossa aplicação para renderizar a maior parte do conteúdo no servidor. Dessa maneira melhoramos a experiência do usuário, além do SEO da página.
O código completo com os exemplos criados nesse artigo estão disponíveis aqui: https://github.com/programai/tutorial-nextjs-searchparams.
Deixe nos comentários qualquer dúvida ou sugestão, e siga-nos nas redes sociais. Valeu demais e até a próxima!

Bacharel em Ciência da Computação pela Universidade Federal do Amazonas, MBA em Gerenciamento de Projetos pela Fundação Getúlio Vargas.
Atualmente trabalha como Gerente de Engenharia na Meliuz.
Com 20 anos de experiência na área, já trabalhou com um pouco de tudo, C, C++, Java, C#, Delphi, Node.js, AWS, PHP, Python, React, Angular, jQuery, e mais um monte de coisa que nem existe mais 😀