Type something to search...
Next.js robots.txt

Next.js robots.txt

robots.txt is the oldest, plainest piece of SEO infrastructure a site can have — a text file at a well-known path telling crawlers what they're allowed to touch. Next.js gives it the same two-tier treatment as every other metadata file convention: write it as a literal static file for the common case, or generate it programmatically when your rules need to vary by environment, by data, or by anything else code can express that a static file can't.

Static robots.txt

User-Agent: *
Allow: /
Disallow: /private/

Sitemap: https://acme.com/sitemap.xml

Placed at the root of app, this is served exactly as written, following the Robots Exclusion Standard — no processing, no transformation, just a static file at the conventional /robots.txt path.

Generating robots.txt with Code

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
      disallow: "/private/",
    },
    sitemap: "https://acme.com/sitemap.xml",
  };
}

This produces output identical to the static version above. The value of the generated form shows up the moment your rules need to reflect something dynamic — an environment variable gating whether staging environments should be fully disallowed, or a disallow list built from a database of paths rather than hand-maintained in a text file. Structurally, robots.js is a special Route Handler, cached by default unless it reaches for a Request-time API or explicit dynamic config — the same caching contract every metadata-file convention in this family shares.

Targeting Specific Crawlers

Passing an array of rule objects (instead of a single object) to rules lets you give different crawlers genuinely different instructions:

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: "Googlebot",
        allow: ["/"],
        disallow: "/private/",
      },
      {
        userAgent: ["Applebot", "Bingbot"],
        disallow: ["/"],
      },
    ],
    sitemap: "https://acme.com/sitemap.xml",
  };
}
User-Agent: Googlebot
Allow: /
Disallow: /private/

User-Agent: Applebot
Disallow: /

User-Agent: Bingbot
Disallow: /

Sitemap: https://acme.com/sitemap.xml

Note that userAgent accepts either a single string or an array — an array applies the same rule set to multiple crawlers at once (as with Applebot and Bingbot sharing one blanket disallow above), rather than requiring a separate rule object per crawler when the rules are identical.

Non-Standard Directives — a Recent, Genuinely Useful Addition

Some crawlers (Seznam's Request-Rate, Yandex's Clean-param) support directives outside the official Robots Exclusion Standard. As of a fairly recent version, Next.js's robots.js supports these via an other field on any rule:

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      { userAgent: "*", allow: "/" },
      {
        userAgent: "SeznamBot",
        allow: "/",
        other: {
          "Request-Rate": "10/1m",
        },
      },
    ],
  };
}
User-Agent: *
Allow: /

User-Agent: SeznamBot
Allow: /
Request-Rate: 10/1m

Two behaviors worth being precise about: keys in other preserve their exact casing as you write them (Next.js doesn't normalize or reformat directive names), and array values emit one line per entry, each scoped correctly within that rule's own User-Agent block rather than bleeding into a different crawler's section.

Next.js does not validate any of this. Values in other pass through completely verbatim — there's no checking that Request-Rate is spelled correctly, formatted the way Seznam actually expects, or even a directive that any real crawler recognizes. If you're using this field, the burden of correctness is entirely on you; consult the specific search engine's own documentation for the exact syntax it expects, since Next.js won't catch a typo or malformed value here the way it would catch a TypeScript type error elsewhere.

The Robots Object Shape

type Robots = {
  rules:
    | {
        userAgent?: string | string[];
        allow?: string | string[];
        disallow?: string | string[];
        crawlDelay?: number;
        other?: Record<string, string | number | Array<string | number>>;
      }
    | Array<{
        userAgent: string | string[];
        allow?: string | string[];
        disallow?: string | string[];
        crawlDelay?: number;
        other?: Record<string, string | number | Array<string | number>>;
      }>;
  sitemap?: string | string[];
  host?: string;
};

Two details buried in that type worth calling out: sitemap accepts either a single string or an array, so a site with multiple sitemap files (perhaps split via generateSitemaps for a large product catalog) can list all of them here rather than being limited to one. And crawlDelay, while present in the type, is worth checking against your target crawler's actual support — not every major search engine respects it, even though the field exists and Next.js will happily emit it.

Version History

VersionChanges
v16.3.0Added the other field for non-standard per-agent directives
v13.3.0robots introduced

Key Takeaways

AspectDetail
Static formapp/robots.txt, served exactly as written
Dynamic formapp/robots.ts/.js, default-exporting a function returning a Robots object
Multiple crawlers, different rulesPass an array to rules, one entry per crawler or crawler group
Non-standard directivesThe other field — passed through verbatim, with zero validation
sitemap fieldAccepts a string or an array — list multiple sitemap files if you have them
CachingCached by default, like every other metadata-file Route Handler

robots.txt is about as low-ceremony as web infrastructure gets, and Next.js's file convention doesn't try to make it more complicated than it needs to be. Reach for the static file until you have an actual reason — environment-specific rules, a dynamically generated disallow list, non-standard directives for a specific crawler — to generate it with code instead.

Tags :
Share :

Related Posts

Can Next.js Be Used with GraphQL?

Can Next.js Be Used with GraphQL?

Next.js and GraphQL are two powerful technologies that have gained significant traction in the web development community. Next.js, a React-based fram

Dive Deeper
How does Next.js differ from Create React App?

How does Next.js differ from Create React App?

In the world of modern web development, React.js has emerged as a dominant force due to its flexibility, performance, and extensive ecosystem. Two po

Dive Deeper
How does Next.js handle image optimization?

How does Next.js handle image optimization?

In modern web development, image optimization plays a critical role in enhancing user experience and improving site performance. Large, unoptimized i

Dive Deeper