Published on

    How I accidentally increase Vercel usage

    • avatar
      Nico Prananta

    Last week I received an email from Vercel saying that many metrics in my project had increased and exceeded the hobby plan limit, including the Function Invocations.

    This surprised me because while my blog has more visitors than before, there's no way that many serverless functions are being called in my project. So what actually happened?

    After looking at the log in the Vercel dashboard, I noticed that the middleware and two other routes were being called a lot.

    The irregularity with the middleware and one of the routes, the /tags/[tag] route, is related. This happened because I made a mistake a few days ago where I accidentally created a ton of wrong tags. These tag pages were unfortunately crawled by bots. That's why there are a lot of calls to the middleware and the /tags/[tag] route.

    The fixes for these are

    1. Exclude the /tags/[tag] route from passing through the middleware.
    2. Prevent the bots from crawling the /tags/[tag] route by returning the correct metadata from the route's layout.
    3. Make sure the /tags/[tag] route returns 404 if the tag doesn't exist by setting the dynamicParams to false in the page.

    The other routes that caused problems were the routes in /experiments/suspense-demo/with-template/admin/[id]/ and /experiments/suspense-demo/with-template/guest/[id]/. Here's the code:

    import Link from 'next/link'
    import { getServerTime } from '../../../get-server-time'
    import { Alert } from '@/components/ui/alert'
    export default async function AdminPage({ params }: { params: { id: string } }) {
      const roles = ['admin', 'guest']
      const role = roles[Math.floor(Math.random() * roles.length)]
      const time = await getServerTime()
      const nextRandomId = Math.floor(Math.random() * 10000)
      return (
        <div className="flex flex-col space-y-2">
          <div className="flex flex-col space-y-2 bg-slate-100 p-4 [&_a]:text-primary-500 [&_a]:underline">
            <p className="font-bold">Admin page {}</p>
            <p>Server: {time}</p>
            <div className="flex flex-row space-x-2">
              <Link prefetch={false} href="/experiments/suspense-demo/with-layout/">
                Next admin page
                Next guest page
                Next random page
          <div className="max-w-lg">
              Notice that when you click any of the links above, the client time in layout above will
              not change because the component is not re-rendered. Unlike with template.
              <br />
              <br />
              In addition, if you type something in the search field, then navigate to another page, the
              text that you typed will not be lost.

    Can you guess what the problem is?

    I've already mentioned on Reddit and Twitter that there's a silver lining to Vercel being expensive. It exposed parts of my code that were inefficient. It's those subtle bugs that only appear because Vercel monitors usage costs and sets a pretty low quota for the free hobby plan.

    But the smart developers on Reddit thought I was an idiot for not writing the efficient code in the first place. So I challenge you, the reader, to find the problem with the above code.

    Click here to read the problem and solution

    There is actually no problem with the code. Just like the tags problem, this is also a bot problem. problem. Since there is a random link to the next page in this code, the bot will keep following the next random page. Hence the increase in the function execution usage.

    To fix this, I exported the same metadata from the layout of the /experiments routes to prevent bots from crawling them. Just to be safe, I also removed the random links to the next routes.

    Because of this "incident", I kind of wish Vercel wouldn't count usage when the project is accessed by bots. If you agree, maybe you can help by tweeting at Vercel to consider this.

    By the way, I'm making a book about Pull Requests Best Practices. Check it out!