Solución:
Terminé capturando el evento de envío y presionando una URL en el enrutador.
import {useState} from 'react'
import {useRouter} from 'next/router'
const preventDefault = f => e => {
e.preventDefault()
f(e)
}
export default ({action = '/search'}) => {
const router = useRouter()
const [query, setQuery] = useState('')
const handleParam = setValue => e => setValue(e.target.value)
const handleSubmit = preventDefault(() => {
router.push({
pathname: action,
query: {q: query},
})
})
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="q"
value={query}
onChange={handleParam(setQuery)}
placeholder="Search"
aria-label="Search"
/>
</form>
)
}
Basado en el sistema de enrutamiento de Next.js y la API del enrutador:
El enrutador Next.js le permite realizar transiciones de ruta del lado del cliente entre páginas, de manera similar a una aplicación de una sola página. Un componente especial de React llamado Enlace se proporciona para realizar esta transición de ruta del lado del cliente.
Router.push también maneja las transiciones del lado del cliente, y este método es útil para los casos en los que next / link no es suficiente.
Por lo tanto, parece que solo puede realizar transiciones del lado del cliente utilizando cualquiera de esas dos formas.
El uso del formulario anterior activará un comportamiento como se describe en los documentos de MDN para el envío de un formulario, ya que no se aplica ninguna de las reglas anteriores:
… El servidor entonces responde, generalmente manejando los datos y cargando la URL definida por el acción atributo, provocando una nueva carga de página (o una actualización de la página existente, si la acción apunta a la misma página).
También encontré otra referencia cercana a su pregunta en el tablero de problemas de Next.js, donde el método preferido a seguir fue el que también describió como una solución.