My take on Next.js
I have been using create-react-app for a while for my side project. Since Next.js 13 was released and is gaining popularity, I decided to give it a try. I usually prefer to learn while doing.
Since I host all my APIs and websites on AWS, I needed to deploy the Next.js app to AWS. I found this helpful guide on how to do it: https://aws.amazon.com/blogs/mobile/amplify-next-js-13/.
Implementing Google Authentication
https://www.telerik.com/blogs/how-to-implement-google-authentication-nextjs-app-using-nextauth
Router and Params
Update query string to persist state across page reload or revisits
- Use 
useRouterto add or update the query string - Use useSearchParams to retrieve a value from the query string
 
'use client'import { useRouter, useSearchParams } from 'next/navigation'
export default function RegistrationsPage() {  const router = useRouter()  const searchParams = useSearchParams()	const [warrantyYear, setWarrantyYear] = useState('-1')	const query = useQuery(['registrations', warrantyYear], async () => {	  const resposne = await querybyWarrantyYear(warrantyYear)	  return resposne.data	}, { enabled: !!warrantyYear })		useEffect(() => {	  setWarrantyYear(searchParams?.get('warrantyYear') || '-1')	}, [searchParams])	  return(    ...		<LabeledListBox		  label='Warranty Year'		  listOptions={warrantyYearListOptions}		  selectedValue={warrantyYear}		  onChange={(e) => {		    setWarrantyYear(e)		    router.push(`/warranty/registrations?warrantyYear=${e}`)		  }}		...  )Parse query string
useSearchParams is a Client Component hook that lets you read the current URLR’s query string.
'use client' import { useSearchParams } from 'next/navigation' export default function SearchBar() {  const searchParams = useSearchParams()   const search = searchParams.get('search')   // URL -> `/dashboard?search=my-project`  // `search` -> 'my-project'  return <>Search: {search}</>}Handle pagination
const Pagination = (props: Props) => {  const router = useRouter()  const path = usePathname()  const first = (props.page - 1) * props.pageSize + 1  const last = first + props.count - 1
  const onClick = (    e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,    direction: 'next' | 'previous'  ) => {    e.preventDefault()    let newPage = direction === 'next'      ? props.page + 1      : props.page - 1    if (newPage < 1) newPage = 1
    const queryString = props.pageSize      ? `page=${newPage}&pageSize=${props.pageSize}`      : `page=${newPage}`
    router.push(`${path}?${queryString}`)  }
  return (		...		<p className="text-sm text-gray-700">      Showing <span className="font-medium">{first}</span> to <span className="font-medium">{last}</span> of{' '}      <span className="font-medium">{props.total}</span> results	  </p>API
API routes provide a solution to build a public API with Next.js.
Any file inside the folder pages/api is mapped to /api/* and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size.
For example, the following API route returns a JSON response with a status code of 200:
import type { NextApiRequest, NextApiResponse } from 'next' type ResponseData = {  message: string} export default function handler(  req: NextApiRequest,  res: NextApiResponse<ResponseData>) {  res.status(200).json({ message: 'Hello from Next.js!' })}