14

I need a way to answer dynamically to the /robots.txt request.

And that's why I've decided to go with getServerSideProps

https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering

If you export an async function called getServerSideProps from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps.

export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

Inside the context parameter we have the req and res objects.

enter image description here

The response for the robots.txt will depend on the req.headers.host value.

For example:

  • www.mydomain.com should render a production robots.txt file
  • test.mydomain.com should render a test robots.txt file (that I'll use on test/staging deployments).

This is my current code:

pages/robots.txt.tsx

import React from "react";
import { GetServerSideProps } from "next";

interface Robots {
  ENV: "TEST" | "PROD"
}

export const getServerSideProps : GetServerSideProps<Robots> = async (context) => {
  const { req, res } = context;
  const { host } = req.headers;

  res.write("XXX");
  res.end();

  return({                // This is unnecessary (but Next.js requires it to be here)
    props: {
      ENV: "TEST"
    }
  });
};

const Robots: React.FC<Robots> = (props) => {  // This is also unnecessary (but Next.js requires it to be here)
  console.log("Rendering Robots...");

  return(
    <div>
      I am Robots 
    </div>
  );
};

export default Robots;  // This is also unnecessary (but Next.js requires it to be here).

It seems to be working:

enter image description here

But the weird part is that Next.js demands me to export a component from that page. And also returns a props: {} object from getServerSideProps is also required.

What is the way to go here? I'm basically using req,res from getServerSideProps to returning something that is not a page. Is this an anti-pattern?

UPDATE

Yes, this is an anti-pattern. You should use rewrites. See the selected answer.

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
  • Have you considered using an [API route](https://nextjs.org/docs/api-routes/introduction) instead? And have a [rewrite](https://nextjs.org/docs/api-reference/next.config.js/rewrites) map `/robots.txt` requests to `/api/robots`. – juliomalves May 04 '21 at 18:15
  • @juliomalves I've thought about that. But I don't know how would Google handle that redirect to `api/robots`. What do you think? – cbdeveloper May 04 '21 at 19:30
  • The rewrite would happen in Next.js so it'd essentially be the same as if you had an actual page for it. – juliomalves May 04 '21 at 19:59
  • @juliomalves I'll test that tomorrow and let you know! Thanks – cbdeveloper May 04 '21 at 20:27
  • 1
    @juliomalves works flawlessly. Exactly what I needed. Feel free to write an answer. That is definitely the recommended approach. Thanks – cbdeveloper May 05 '21 at 09:29

1 Answers1

36

You can use an API route instead for the logic and have a rewrite map /robots.txt requests to /api/robots in your Next.js config file.

// next.config.js
module.exports = {
    // ...
    async rewrites() {
        return [
            {
                source: '/robots.txt',
                destination: '/api/robots'
            }
        ];
    }
}
// /pages/api/robots
export default function handler(req, res) {
    res.send('XXX'); // Send your `robots.txt content here
}
juliomalves
  • 42,130
  • 20
  • 150
  • 146
  • 1
    Can someone say more about why OP's solution of getServerSideProps is an anti-pattern? Wouldn't using the API not take advantage of next's static build caching? – Jack Ratner Nov 04 '21 at 18:30
  • @JackRatner OP expressly mentioned _"I need a way to answer dynamically to the `/robots.txt` request"_ meaning the robots file should be created dynamically upon request. Statically caching it would lose the dynamic aspect of it. – juliomalves Nov 07 '21 at 16:44
  • @JackRatner _"why OP's solution of getServerSideProps is an anti-pattern?"_ - I wouldn't necessarily call it an _anti-pattern_. While `getServerSideProps` _could_ be used to generate these kind of files, that's not the proper use-case for it. `getServerSideProps` is supposed to be used in `page` components, to allow those pages to be server-side rendered. Using an API route to generate dynamic `robots.txt` or `sitemap.xml` files is more idiomatic. – juliomalves Nov 07 '21 at 16:57
  • 1
    But even Next.js is using ```getServerSideProps``` in their Sitemaps example: https://nextjs.org/learn/seo/crawling-and-indexing/xml-sitemaps – Veljko Blagojevic Oct 19 '22 at 14:51
  • @VeljkoBlagojevic It's certainly possible, and you could use `getServerSideProps` for that purpose. I still believe using an API route makes more sense. – juliomalves Oct 19 '22 at 14:54
  • 1
    Many thanks I combined this with https://github.com/vercel/next.js/discussions/15453#discussioncomment-987749 gave me the perfect solution – Matthew Barnden Nov 17 '22 at 16:25