Chapter 11: Different Deployment Platforms

In the previous chapters, we saw how Next.js works, how to optimize it for SEO, how to deal with performance, how to adopt UI frameworks, and how to fetch data on both the client and server sides, eventually being able to create a fantastic web application. But then, we have a problem: how should we ship it to production? There are many different hosting providers, cloud platforms, and even Platform as a Service (PaaS) solutions out there; how do we pick one?

In this chapter, we will see how to choose the right deployment platform.

We will look at the following in detail:

  • How choosing the right deployment platform could affect performance
  • How to decide between different cloud solutions
  • What are the most popular alternatives for hosting a Next.js app?

By the end of this chapter, you'll be able to deploy any Next.js application to any host, knowing how to choose the right provider from the most popular hosting solutions.

Technical requirements

To run the code examples in this chapter, you need to have both Node.js and npm installed on your local machine.

If you prefer, you can use an online IDE, such as https://repl.it or https://codesandbox.io; they both support Next.js, and you don't need to install any dependency on your computer. As with the other chapters, you can find the code base for this chapter on GitHub: https://github.com/PacktPublishing/Real-World-Next.js.

A brief introduction to different deployment platforms

While thinking about a new web application, we have many things to consider. For example, how do we want to render its pages, which styling method do we want to adopt, where does data come from, how do we manage the application state, and where do we want to deploy the application itself?

Focusing on that last part, we could split one problem into two: where do we want to deploy our application and how do we want to do it?

In fact, most of the time, choosing a deployment platform also means selecting a slightly different deployment method. There are specific cloud platforms, such as Vercel, Netlify, and Heroku, where the deployment process is standardized and incredibly simplified to be accessible for everyone. With other cloud providers, such as AWS, Azure, and DigitalOcean, you have complete control over the whole deployment process. Unfortunately, in many cases, you have to implement this process on your own or use third-party software.

The number of cloud infrastructures has drastically increased over the last few years, and the competition has brought some great innovation to this sector. Even though there are many alternatives, we will be focusing on the most popular ones, as we're more likely to find more documentation and support for them.

In the next section, we will discuss the most prominent platform to deploy a Next.js application to: Vercel.

Deploying to the Vercel platform

Develop, preview, ship is not just a motto. It's the perfect description of the company that developed Next.js (alongside many other open source libraries) and an excellent cloud infrastructure for deploying and serving web applications.

With Vercel, you almost don't need to configure anything. You can deploy your web application from the command line using their CLI tool, or create an automatic deployment after a push to the main Git branch.

One thing to know before getting started with Vercel is that the platform is built specifically for static sites and frontend frameworks. Unfortunately, that means that custom Node.js servers are not supported.

But at this point, you might be wondering whether only statically generated or client-side-rendered Next.js websites are supported. The short answer is no. In fact, Vercel supports server-side-rendered pages by serving them via serverless functions.

What Does "Serverless Function" Mean?

When talking about "serverless functions," we refer to a single function (written in any programming language) that gets invoked on a managed infrastructure. In fact, it's called "serverless" because we just have to write the function without really thinking about the server executing it. Unlike traditional servers, where we typically pay an hourly rate (for example, we could pay $1 for every hour, even when the server is not processing any data), serverless functions have a different pricing model: we pay them a fraction of a cent for each execution, depending on the execution duration, memory usage, and other similar metrics. For example, at the time of writing, AWS Lambda (the most popular serverless environment) costs $0.20 for every million requests and $0.0000000021 for every millisecond of duration (when allocated 128 MB of memory). As you can imagine, this pricing model can be really attractive compared to more traditional alternatives, as you only pay for what you actually use.

Vercel does an incredible job of setting up serverless functions for us when deploying a Next.js application, so we don't have to worry about them; we just have to concentrate on the web application we're building.

Deploying an application to Vercel is pretty straightforward. We can proceed in two different ways:

  • By linking our GitHub, GitLab, or Bitbucket repository to Vercel. Every time we create a pull request, Vercel will deploy a preview application to test the features we just developed before publishing them to production. Once we merge or push to our main branch, Vercel will automatically deploy the application to production.
  • We can do everything manually from the command line. For example, we can decide to create a preview application, preview it locally, or publish it to production directly from our terminal using the Vercel CLI tool, where typing vercel --prod is enough to promote the app to production.

Either way, the developer experience is outstanding, so feel free to test both deployment strategies and find your favorite one.

Among all the possible alternatives for deploying and serving Next.js applications, Vercel is probably one of the easiest ones. Also, it allows you to gain access to the analytics module (do you remember we talked about it in Chapter 10, Working with SEO and Managing Performance?), which can be incredibly useful to measure frontend performances over time. That will help us keep an eye on frontend optimization, which other platforms don't do (also, it's something fundamental!).

If you're looking for something comparable to Vercel, a good alternative you may consider is Netlify. The whole deployment workflow is quite similar to Vercel's one, and the developer experience is just as phenomenal. However, I'd encourage you to consider the pricing model differences before deciding on either platform.

Both Vercel and Netlify also work incredibly well when deploying a static website. But there, the competition with other platforms will grow; we'll see some alternatives in the next section.

Deploying a static site to a CDN

When talking about a CDN (short for content delivery network), we refer to a geographically distributed network of data centers used to achieve high availability and performance when serving content to users in any part of the world.

To keep it simple, let's give an example. I currently live near Milan, Italy, and I want my web application to be used in potentially any part of the world. So, where should I host it from a geographical point of view?

Certain providers, such as Amazon AWS, DigitalOcean, and Microsoft Azure (and many more), will let you choose a specific data center to serve your application from. For example, I could select AWS eu-south-1 (Milan, Italy), ap-northeast-2 (Seoul, South Korea), or sa-east-1 (São Paulo, Brazil). If I choose to serve my web application from Milan, Italian users will notice a very low latency when trying to reach the web application; it is geographically located very close to them. The same could happen for French, Swiss, and German users, but for people living in Asia, Africa, or the Americas, it will be the opposite. The further you are from the data center, the greater the latency, leading to lousy performance, poor client-to-server request latency, and so on. If we think of static assets, such as images, CSS, or JavaScript files, this will be even clearer.

Heavy file size + data center distance = bad download performance. It's quite easy, isn't it?

CDNs solve this specific problem by providing a whole infrastructure distributed in (almost) every continent. Once you deploy your static asset to a CDN, it will be replicated across all the regions in the network, making it available closer to your users in any part of the world.

If you look at Next.js' statically generated websites, you will quickly notice that there is no need for a server to render the pages at request time. Instead, the website is entirely generated and statically rendered at build time, so we eventually end up with a collection of static HTML, CSS, and JavaScript files that can be deployed to a CDN.

If we're in that situation, then we're in luck. We're about to achieve the best possible performances by serving static HTML pages from a CDN. But which CDN should I choose? We'll find it out in the next section.

Choosing a CDN

When looking for a CDN to deploy our web application, we will find many different alternatives. Prominent players in this area are (but are not limited to) Amazon AWS, Microsoft Azure CDN, and Cloudflare. Of course, there are many other alternatives, but these are the ones I've tried and had great experiences with, so I feel confident recommending them to you.

The CDN deployment adds some configuration steps, but spending a bit more time to achieve the best possible performance might be worth it.

Talking about AWS, for instance, the procedure won't be as straightforward as the Vercel one. We would need to build a pipeline (with either GitHub Actions or GitLab Pipelines, and so on) to statically generate the web application, then to push it to AWS S3 (a service used for storing static assets), and eventually use a CloudFront (AWS CDN) distribution to let users reach these static assets over HTTP requests. We would also need to link our CloudFront distribution to a domain name, and we can do that using AWS Route 53 (an AWS proprietary DNS service).

Cloudflare, in comparison, makes things a bit easier. It has a more straightforward UI, called Cloudflare Pages, that can help us link our project to a Git repository and automatically deploy a new website version every time we push new code to any branch. Of course, every time we push some code to the main branch, it will be published in production; if we want to preview some features living on feature branches, we can just push our code there and wait for Cloudflare to publish a preview deployment, just like Vercel does.

Microsoft Azure provides another exciting approach. We can enter the Azure portal (the Azure administration dashboard), create a new resource, select "static web app" as the resource type, and enter the required data to configure it. After that, we can link our GitHub account, making automatic deployments available just like we did on Cloudflare and Vercel. Azure will create a GitHub workflow file for us so the build phase will run on GitHub and push the content to Azure as soon as it succeeds.

Now, you might be wondering how to choose the best CDN among the ones listed previously. Well, they're all excellent, but there's a way to determine which one best suits our needs.

AWS, for instance, might look like the most complicated one. But if we already have an AWS infrastructure, it would make things easier for us to set up a deployment there. The same applies to Microsoft Azure, where we might already have existing projects running on this platform, and we don't want to move just one web application outside of it.

Cloudflare, instead, can be the perfect solution for all static websites that don't need to rely on other services, except for serverless functions (Cloudflare offers a serverless function service called Cloudflare Workers) and other similar services that you can find at https://developers.cloudflare.com.

Even though there are ways to execute serverless functions decoupled from the static website (by using AWS Lambda, Azure Functions, Cloudflare Workers, and so on), there are times when we need to create dozens or even hundreds of serverless functions. Organizing such deployments can be challenging, especially if we're working in a small team without support from someone who's really into DevOps.

Other times, we just need server-side rendering alongside statically generated pages, and we need to deploy an application where we can use Node.js code at runtime. One interesting approach is to deploy the website in a completely serverless fashion.

There is an open source project called serverless-next.js (https://github.com/serverless-nextjs/serverless-next.js) that can help us achieve that result. It works as a "Serverless component" (in that case, Serverless is the name of an npm library used to deploy code to any serverless platform) that will configure a deployment on AWS by adapting it to the following rules:

  • SSR pages and API routes will be deployed and served by AWS Lambda (serverless functions).
  • Static pages, client assets, and public files will be deployed to S3 and automatically served by CloudFront.

This approach will lead to a kind of hybrid deployment where we always try to achieve the best possible performances of each type of request. SSR and API pages (which need a Node.js runtime) will be served by a serverless function, everything else from a CDN.

Don't worry if that sounds complex because it isn't. But if you feel like it would be an over-engineered part of your application life cycle (and you still need server-side rendering and API routes), you may want to consider other approaches. We will discuss how to deploy an SSR Next.js application to any platform correctly in the next section.

Deploying Next.js on any server

So far, we've seen some alternatives for deploying our Next.js application to CDNs and managed infrastructures, such as Vercel and Netlify. Still, there is another alternative that we haven't considered yet; what if we want to deploy our application to our private server?

Even though this is a common situation, it is also the most complex one by far. While platforms such as Vercel, Netlify, and Heroku manage the server for us, sometimes we may want to host our application on a private server where we have to control everything independently.

Let's have a quick recap of what the previously mentioned managed platforms can do for us:

  • Automatic deployments
  • Rollback to previous deployments
  • Automatic deployments for feature branches
  • Automatic server configuration (Node.js runtime, reverse proxy, and so on)
  • Built-in scaling capabilities

By choosing a custom server, we have to implement all these features on our own. But is it worth it? Well, it depends. When working in a large company that already has a significant infrastructure up and running on a given cloud provider (be it Amazon AWS, Google Cloud, Microsoft Azure, and so on), it might make sense for us to identify the best solution for deploying our Next.js application in the same infrastructure.

If we're working on a side project or a small business website or starting a new web application from scratch, we could consider alternatives, such as managed platforms or CDNs, but we've already talked about that.

Let's pretend for a moment that the choice has been made, and we have to deploy our application to either Amazon AWS, Google Cloud, or Microsoft Azure. How do we approach deployment and hosting from there?

The first thing to consider is how we want to serve our application. Starting with an empty server means that we have to manually set up a bunch of stuff to make it ready to serve a Node.js application. That includes (but is not limited to) the following:

  • The Node.js runtime: Node.js is not pre-installed on every operating system, so we'll need to install it to serve API and server-side-rendered pages.
  • A process manager: If you have already worked with Node.js in the past, you may know that if the main process crashes, the entire application will stay down until we manually restart it. That is due to the Node.js single-threaded architecture, and it's unlikely to change in the future, so we need to be prepared for this possibility. A popular approach to solving that problem is using a process manager such as PM2 (https://github.com/Unitech/pm2), which monitors the Node.js processes and manages them to keep the application up and running. It also provides many other additional features for handling any Node.js program, so if you're interested in that, I'd recommend you read the official documentation at https://pm2.keymetrics.io.
  • A reverse proxy: Even though we could easily set up any Node.js application to manage incoming HTTP requests, it is a best practice to put it behind a reverse proxy such as NGINX, Caddy, or Envoy. This adds an extra layer of security, other than valuable features we don't want to compromise on, but also means we have to maintain a reverse proxy on our server.
  • Setting up firewall rules: We need to open the firewall to accept incoming HTTP requests to the :443 and :80 ports.
  • Setting up an efficient deployment pipeline: We could use Jenkins, CircleCI, or even GitHub Actions. But this is another thing to take care of.

Once we're done setting up the whole environment, we should also consider that we may need to replicate that same environment on another server as soon as we need to scale our infrastructure to accept more and more incoming requests. It might be pretty easy to replicate it on a new server, but what if we need to scale on dozens of new machines? And what if we need to upgrade the Node.js runtime or the reverse proxy on all of them? Things are getting more complicated and time-consuming, so we may want to look for an alternative approach, and that's what we're going to talk about in the next section: how to deploy our Next.js application to any server by using Docker.

Running Next.js in a Docker container

Docker, and virtualization in general, has changed forever the way we build and deploy our applications. It provides a set of useful utilities, commands, and configurations to make our build reproducible on any server, making our application available on almost every operating system by creating a virtual machine running our program (or web application).

In Case You Are New to Docker

Docker is an important tool to consider when building and deploying any computer program (a web application, database, or anything else). If you're new to this technology, I highly recommend reading the official Docker documentation at https://www.docker.com before starting to use it. If you're interested in a hands-on approach to learning Docker, I'd also recommend you read Mastering Docker – Fourth Edition by Russ McKendrick (https://www.packtpub.com/product/mastering-docker-fourth-edition/9781839216572); it provides a complete guide to getting started and understanding Docker.

Running Next.js in Docker is relatively straightforward. A very basic Dockerfile is composed of the following commands:

FROM node:16-alpine

RUN mkdir -p /app

WORKDIR /app

COPY . /app/

RUN npm install

RUN npm run build

EXPOSE 3000

CMD npm run start

It's almost effortless, isn't it? Let's break it down into small steps:

  1. First, declare which image we want to run our server in. In this case, we're choosing node:14-alpine.
  2. It is a best practice to create a new working directory, so as a first step, create it and name it /app.
  3. Choose /app as our working directory.
  4. Copy all the content of our local directory into the Docker working directory.
  5. Install all the required dependencies.
  6. Build Next.js inside the container's working directory.
  7. Expose port 3000 to be reached from outside the container.
  8. Run the start script for booting the Next.js built-in server.

We can test the previous Dockerfile by creating a new, empty Next.js app running the following command in a new directory:

npx create-next-app my-first-dockerized-nextjs-app

Let's create a Dockerfile with the content we just discussed. We should also create a .dockerignore file containing node_modules and the Next.js output directory so that we won't be copying them into the container:

.next

node_modules

We can now proceed by building the Docker container:

docker build -t my-first-dockerized-nextjs-app .

We're tagging it with a custom name, in this case, my-first-dockerized-nextjs-app.

Once the build succeeds, we can run the container as follows:

docker run -p 3000:3000 my-first-dockerized-nextjs-app

We are finally able to reach our web application at http://localhost:3000!

Starting from that simple configuration, we will be able to deploy our application to any managed container service (such as AWS ECS or Google Cloud Run), any Kubernetes cluster, or any machine with Docker installed.

Using containers in production has many benefits, as we only need a very simple configuration file for setting up the virtualization of a Linux machine to run our application in. Whenever we need to duplicate, scale, or reproduce our build, we can simply do that by sharing the Dockerfile and executing it, making the whole process incredibly straightforward, scalable, and easy to maintain.

That said, do we always need Docker? Let's discuss this in the summary for this chapter, right in the next section.

Summary

In this chapter, we've seen different deployment platforms for our Next.js application. There's no perfect solution for building and deploying Next.js apps, as it depends on the specific use case and challenges that every project brings.

Vercel, Netlify, and Heroku (just to quote some) are all excellent alternatives for quickly deploying a Next.js application to production. On the other hand, Cloudflare Pages, AWS S3 and AWS CloudFront, and Microsoft Azure CDN can really provide excellent performance for our static sites, which competes with all the other great solutions we've seen in this chapter when it comes to serving a statically generated website.

Docker is probably one of the most flexible solutions. It allows us to deploy our application everywhere, making it easy to replicate the production environment on every machine.

Again, there's no "perfect" solution for deploying a Next.js application, as the competition in this field is extremely strong, and many companies provide excellent solutions to simplify our lives as developers and make our browsing experience always better as users.

The best suggestion I can give when deciding where to deploy a Next.js application is to consider the following aspect: how big is the team I'm working in? While solutions such as Vercel, Netlify, Heroku, and Cloudflare are well suited for both little and big teams, there are other providers where the required knowledge, skillset, and capacity are way higher. Setting up an AWS EC2 instance or a custom machine on DigitalOcean or Google Cloud gives us much more control over the whole application life cycle, but the cost (in terms of configuration, setup, and required time) is considerable.

On the other hand, when working in big companies where there's a dedicated DevOps team that can take care of the release process for the application, they might prefer to adopt custom solutions where they have more and more control.

But even if we're working alone, we can choose to deploy our applications to a custom cloud infrastructure. If we're doing that, we should make sure we're not unintentionally reinventing the wheel by recreating infrastructures that Vercel, Netlify, Cloudflare, and so on can provide even on a free plan.

We've made some significant progress so far. We learned the basics of the framework and how to integrate it with different libraries and data sources, and now we also know how to choose a deployment platform for any need.

Starting from the next chapter, we will build some real-world applications that will allow us to understand the real-world challenges we will face when creating production-ready web applications in Next.js.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.17.40