Next.js Edge API Routes
by mmyoji
2 min read
Conclusion
runtime: "experimental-edge" behaves differently from runtime: "nodejs".
It returns different HTTP response headers and I will explain the detail in this post (although this might be wrong partially.)
My Concern
Next.js v12.2 introduces Edge Runtime.
I'd just understood it couldn't use Node.js standard APIs and was lightweight.
But I was not sure how this worked and how differed from runtime: "nodejs" and
wondered whether this affected when choosing self-hosted.
The official document says like this:
Edge API Routes can stream responses from the server and run after cached files (e.g. HTML, CSS, JavaScript) have been accessed.
...OK, I will test the new API routes!
Test Code
Set experimental.runtime: "nodejs" in next.config.js
pages/api/test.ts uses runtime: "nodejs":
import { NextApiHandler } from "next";
const handler: NextApiHandler = async (_req, res) => {
  res.status(200).json({ name: "Jim Halpert" });
};
export default handler;
pages/api/test-edge.ts uses runtime: "experimental-edge":
import { NextApiHandler } from "next";
export const config = {
  runtime: "experimental-edge",
};
const handler: NextApiHandler = async (_req, res) => {
  // see: https://nextjs.org/docs/api-routes/edge-api-routes#json-response
  return new Response(
    JSON.stringify({
      name: "Jim Halpert",
    }),
    {
      status: 200,
      headers: {
        "Content-Type": "application/json; charset=utf-8",
      },
    },
  );
};
export default handler;
Both of them returns the same response body.
Result
I picked up only response headers part.
curl -v http://localhost:xxx/api/test
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< ETag: "16-DlZOPLD8Q/zEnYFRYsdmnqlUPWI"
< Content-Length: 22
< Vary: Accept-Encoding
< Date: Thu, 30 Jun 2022 11:42:50 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
curl -v http://localhost:xxx/api/test-edge
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Date: Thu, 30 Jun 2022 11:43:39 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
experimental-edge runtime:
- lacks 
ETag,Content-Length, andVaryheaders - adds 
Tranfer-Encoding: chunkedheader 
Transfer-Encoding: chunked sends HTTP repsonse as chunk (or stream)
according to
MDN doc.
- With this header, 
Content-Lengthis omitted from the doc. - It's understandable 
Vary: Accepct-Encodingis omitted for this endpoint becauseTransfer-Encodingis specified (chunks are always sent). - The reason 
ETagis dropped, I guess, might be that the endpoint could not end in a single request. 
Again, my understanding for HTTP is not enough and this post might be wrong. Please check correct sources by yourself.