Vercel VS Edge VS Next. What is Edge, Why, How and Where

Edge runtime. One of the main functionalities of Vercel, the company that developed and is developing next.js. However, its influence on edge runtime has gone far beyond its frameworks and utilities. Edge runtime works in the recently acquired Vercel Svelte, and in nuxt, and in more than 30 other frontend frameworks. This article will be devoted to edge runtime – what it is, how it is used in Vercel, what capabilities it complements next.js with, and what decisions I made to expand these capabilities.

Vercel Edge Network

In simple terms, Edge runtime is a content delivery network (CDN/Distributed Infrastructure), that is, many points around the world. Thus, the user does not interact with a single server (which may be lying in a company office on the other side of the world), but with the network point closest to it.

The difference between accessing the server directly or via the Edge Network

The difference between accessing the server directly or via the Edge Network

At the same time, these are not copies of the application, but separate functionality that can work between the client and the server. That is, these are a kind of mini-servers with their own features (which will be discussed later).

This system allows users to go not directly to your distant server, but to a nearby point. It makes decisions on a/b tests, checks authorization, caches requests, returns errors and much more. Only after that, if necessary, the request will go to the server, immediately for the necessary information. Otherwise, the user in the shortest possible time receives an error or, for example, a redirect.

Processing requests via the Edge Network

Processing requests via the Edge Network

Of course, this concept itself is not Vercel's merit. CloudFlare, Google Cloud CDN and many other solutions can do this. However, Vercel, with its influence on frameworks, has taken this to a new level, deploying not just an intermediate router at the CDN level, but making mini-applications that can even render pages at the point closest to the user. And most importantly, this can be done simply by adding familiar JS files to the project.

Edge Runtime in Next.js

In next.js, perhaps the main functionality of this environment is the middleware file. Any segment (API or page) can also be executed in edge runtime. But before describing them, a little about the next.js server.

Next.js is a full-stack framework. That is, it contains both a client application and a server. When you run next.js (next start) – the server itself is launched and is responsible for issuing pages, API operation, caching, rewrites, etc.

It all works in the following order:

  1. headers from next.config.js;

  2. redirects from next.config.js;

  3. Middleware;

  4. beforeFiles rewrites from next.config.js;

  5. Files and static segments (public/, _next/static/, pages/, app/etc.);

  6. afterFiles rewrites from next.config.js;

  7. Dynamic segments (/blog/[slug]);

  8. fallback rewrites from next.config.js.

When it is determined that the current request reaches exactly the segment (and not, for example, before the redirect) – its processing starts (it is either returning a statically assembled segment, or reading from the cache, or executing it and returning the result).

In Vercel, this entire cycle can probably happen in edge runtime. However, the really interesting points here are points 3, 5 and 7.

The middleware itself in the basic implementation looks like this:

import { NextResponse, type NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
    return NextResponse.redirect(new URL('/home', request.url));
}

In it, for example, you can:

  • Make requests (eg to find out data from third party services);

  • Perform a rewrite or redirect (eg to conduct an A/B test or check authorization);

  • Return a certain body (eg to display a basic stub in certain situations);

  • Read and/or edit headers and cookies (eg save or read access information).

You can read more about the areas of application in next.js documentation on middleware.

The same can be done in segments (i.e. API and Pages). For the segment to work in edge runtime, you need to export from the segment file:

export const runtime="edge";

This way the segment will be executed in edge runtime, not on the server itself.

However, it is worth making an important reservation. Everything described above is not a full-fledged edge runtime in itself. In the Edge Network, this will be distributed only when the service is deployed to Vercel.

Also, in addition to all these capabilities, the edge runtime has a number of limitations. For example, despite the fact that when running an application outside of Vercel, the edge runtime is part of the server – it will not be possible to interact with this server. And this is done this way because it was developed specifically for the Vercel Edge Network.

Edge Runtime Concept in Vercel

As already mentioned, edge runtime can be called mini-applications. And they are mini because they run on node.js V8 (on which, for example, Google Chrome and Electron work). This is their key feature, on which not only the possibilities of the previous section depend, but also the prohibitions.

Namely, in edge runtime it is not possible:

  • Perform actions with the file system;

  • Interact with the server environment;

  • Call require. Only ES modules can be used. This has additional restrictions on third-party solutions.

A full list of supported APIs and limitations can be found at next.js documentation page.

Thus, Vercel Edge Network can be responsible for, for example:

Edge runtime is the first stage of segment processing and is most effective for situations where all processing can take place inside the edge container. For example, for redirects or returning cached data. The entire processing process in Vercel usually works in the following order:

Vercel Request Processing Procedure, source - vercel.com

Vercel Request Processing Order, source – vercel.com

Expected changes in edge runtime

Despite the fact that edge runtime is one of the key features of Vercel as a hosting service, the team is actively reviewing it. Not only the application itself, but also the need in general. Thus, recently VP Vercel – Lee Robinson in his tweet shared that Vercel [как компания] stopped using edge runtime in all its services and returned to nodejs runtime. The team also expects that the experimental partial prerender (PPR) will be so effective that generation at edge runtime will finally lose its value.

And it was PPR, together with advanced caching, that pushed edge runtime into the background. That is, before, the page was rendered entirely both on the server and in edge runtime. Edge runtime won precisely due to its closer location. Now, pages are mostly pre-generated. Then, upon request, individual dynamic parts are rendered and cached. The cache, in turn, is different for each point in edge runtime, while on the server it is the same for all users.

And of course, the server has access to the environment, database and file system. Therefore, if the page needs this data, nodejs runtime wins significantly (collecting everything in one environment is faster than making requests to the server from the edge environment every time).

Vercel will likely introduce new priorities in their pricing, rebuilding them around partial prerendering. Perhaps with their change there will be fewer tweets with bills in the tens of thousands of dollars (but that's not certain).

$100,000 Vercel usage invoice, source: tweet from Cara founder.

In addition, the Next.js team recently shared tweet about reworking middleware. It is very likely that it, as well as segments, will be given a choice of execution environment. Again, considering that outside of Vercel, middleware works as part of the server – this is a very logical decision. It is also possible that along with the changes, a separate middleware for API routes will be added.

Edge Runtime Extension

I am the author of a number of packages for next.js nimpl.tech. I already mentioned getters with information about the current page in the article “Next.js App Router. User experience. The path to the future or a wrong turn”, the translation library in “More libraries for the library god or how I rethought i18n [next.js v14]”, cache packages in “Next.js Caching. A Gift or a Curse”. But this family also includes packages built specifically for edge runtime – router And middleware chain.

@nimpl/router

As mentioned, the edge runtime works best if it can handle the entire request in a self-contained mini-application. In all other cases, this is an unnecessary step, since the request will still go to the server, but via a longer path.

One of these tasks is routing. Routing also includes rewrites, redirects, basePath and i18n from next.config.js.

Their main problem is that they are set only once – in the configuration file – for the entire application, and i18n is full of bugs. Therefore, in App Router there is no information about the i18n option and the documentation recommends using middleware for this task. But such a separation means that redirects from the config and i18n routing from the middleware are processed separately. This can lead to double redirects (first a redirect from the config will be performed, then a redirect from the middleware) and various unexpected artifacts emerge.

To avoid this, all this functionality should be collected in one place. And, as the documentation for i18n recommends, such a place should be middleware.

import { createMiddleware } from '@nimpl/router';

export const middleware = createMiddleware({
    redirects: [
        {
            source: '/old',
            destination: '/',
            permanent: false,
        },
    ],
    rewrites: [
        {
            source: '/home',
            destination: '/',
            locale: false,
        },
    ],
    basePath: '/doc',
    i18n: {
        defaultLocale: 'en',
        locales: ['en', 'de'],
    },
});

The usual Next.js redirects, rewrites, basePath and i18n settings, but at the edge runtime level. @nimpl/router package documentation.

@nimpl/middleware-chain

Working with ready-made solutions or creating my own – time after time I encountered the problem of combining them in one middleware. That is, when two or more ready-made middlewares need to be connected to one project.

The problem is that middleware in next.js is not the same as in express or koa – it immediately returns the final result. So each package simply creates the final middleware. For example, in next-intl it looks like this:

import createMiddleware from 'next-intl/middleware';
export default createMiddleware({
    locales: ['en', 'de'],
    defaultLocale: 'en',
});

I'm not the first to encounter this problem, and there are ready-made solutions in npm. They all work through their own APIs – made in the express style or in their own vision. They are useful, well implemented and convenient. But only in cases where you can update each used middleware.

However, there are many situations where you need to add ready-made solutions. Usually in the tasks of these solutions you can find “add support for adding chain package A”, “work with chain package B”. It is for such situations that the @nimpl/middleware-chain.

This package allows you to create a chain of native next.js middleware without any modifications (that is, you can add any ready middleware in a chain).

import { default as authMiddleware } from "next-auth/middleware";
import createMiddleware from "next-intl/middleware";
import { chain } from "@nimpl/middleware-chain";

const intlMiddleware = createMiddleware({
    locales: ["en", "dk"],
    defaultLocale: "en",
});

export default chain([
    intlMiddleware,
    authMiddleware,
]);

The chain processes each middleware in turn. During processing, all modifications are collected until the chain is complete or until some element of the chain returns FinalNextResponse.

export default chain([
    intlMiddleware,
    (req) => {
        if (req.summary.type === "redirect") return FinalNextResponse.next();
    },
    authMiddleware,
]);

It's not Koa or Express, it's a package for next.js, in its unique style and API format. Package documentation @nimpl/middleware-chain.

Well, in conclusion, I will allow myself to give a few links.

My Habr with other useful articles | nimpl.tech with package documentation | github with star button | X with rare posts | in just to be


The dot map used as a background for the images at the beginning of this article was made mocrovector from freepik.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *