May 5, 2021 - 6 min read

photo of Tom

Tom

Consultant

Reverse Engineering Vercel App Deployment

Share

Over the last couple of years, Next.js has become a front-runner in my eyes when it comes to building isomorphic javascript applications because of its flexibility. Whether you need a statically generated marketing page or fully dynamic web applications - it can do it all. After having used it for a few projects now and keeping up to date with the latest enhancements and updates, it seemed like the perfect tool to help with our latest project - taking Cineplex’s web front-end properties to the next level.

We were able to utilize a lot of what Next.js had to offer out of the box, but when it came to deployment, we couldn’t go with their recommended solution Vercel because of Cineplex’s existing digital ecosystem. We had to get a bit creative and now that we’ve recently launched, we wanted to share our learnings on building and deploying a Next.js application on Microsoft Azure.

What Cineplex is working towards

Currently, cineplex.com is deployed as a .NET MVC application that will render pages server-side on every request. This performs well under most circumstances but under extreme load (i.e. when the new Star Wars movie is announced) the server(s) needs to scale up significantly, which increases cost and potential for failure or dropped requests. They are currently undergoing a modernization effort across the board and are consulting with Nascent on how to improve performance, reliability, time to market, and developer experience for their user-facing web applications. Deploying Next.js has been our first step in moving Cineplex closer to their goal.

Why Next.js was the best solution for the job

Scalability & performance under load

The majority of the traffic to cineplex.com (with the exception of ticket purchases) is directed to their home page, film pages, and theatre pages. These pages hold content that doesn’t change very often. As a result, we can generate HTML/CSS/JS at build time and serve via a CDN to provide a lightning-fast experience that scales.

Onboarding & maintenance

By sticking to the practices and defaults that Next.js provides, we’re able to leverage their robust framework documentation for onboarding & reference. Maintenance is relatively easy as long as we keep our core dependencies up to date - the most critical are managed by the Next.js framework itself.

Developer experience

Next.js has build tools integrated with the framework, including Typescript support, which makes installing, building, and running painless. Additionally, developers don’t need to mess around with webpack/babel config issues, as everything is abstracted through the framework. Error handling and sourcemaps integration is also included to allow for straightforward troubleshooting.

What do you do when you can’t use Vercel?

Cineplex’s digital properties are, for the most part, ingrained in the Microsoft Azure ecosystem. For security, operational, and business reasons it makes the most sense to keep any new infrastructure as a part of the same ecosystem. That way managing connections between applications, permissions, hosting costs, and budgets can all happen in one place. This requirement introduced a challenge we had not yet encountered in our experience with Next.js. Up until this point we’d been able to follow their recommendation and use Vercel (formerly Zeit) for zero-configuration deployment.

So the question was: how can we break away from Vercel and use Azure infrastructure products to deploy our Next.js applications, while still leveraging all the great optimizations built into the framework?

Option 1: Azure Static Web Apps

At the time of writing this post, the Azure Static WebApps is still in preview - not recommended for production use. This product is also for the deployment of only static pages which eliminates some of the flexibility and dynamic page generation that Next.js can do. We need the ability to use a hybrid approach - combining some statically generated pages with server-side rendered pages in the same application.

Option 2: Azure App Service with Azure CDN

Deploying a Node.js server to an Azure App Service seemed to be our best option. We could run next build in our CI/CD pipeline to generate any static pages at build time and then have a Node.js server running on a Linux App Service instance to handle incremental static regeneration as well as server-rendered pages. By using next start to spin up our server, Next.js will serve the pre-built html/JS in the .next directory while still being able to build and return pages on the fly as needed.

Option 2 gives us a server now that will serve pre-rendered content, server-side rendered content, and support incremental static regeneration. This would have been a reasonable configuration to run in a production environment depending on the demands of the application. However, a reasonable solution was not our target - we wanted to be able to optimize performance as much as possible.

How do we harness the power of Next.js with Microsoft Azure?

You may have heard Node.js is not the best solution for serving static files. So, our next goal was to find a more performant way of serving all that static content. We set out to replicate the Vercel edge network caching behaviour so our Node.js server isn’t a bottleneck for serving static files.

My initial thoughts were to have some mechanism that can take the static output from the .next directory and move it to some Azure blob storage and then use a CDN (Content Delivery Network) to serve those static files. Reading more about Azure CDN actually made me realize I didn’t fully understand how a CDN even works.

I always assumed a CDN was only used in conjunction with some static file/blob storage (i.e. Amazon S3, Azure Blob storage). Looking deeper at how a CDN worked led me to see that it can be used with any origin server, not necessarily some purely static file server. Each incoming request uses the CDN POP (point of presence) node as a proxy to the actual node.js server and the response is cached at that POP node to serve any subsequent requests - no matter whether the response is HTML/CSS/JS/JSON/Images etc.

This diagram shows a simplified example of how a CDN can reduce load on any server and leverage nodes in data centres all over the world to give fast response times regardless of a user or origin server’s physical location: Image caption

In practice, we created an Azure CDN endpoint that uses the Node.js App Service as its origin which gave us high-performance edge network capabilities out of the box.

There were only a couple of customizations we needed to add to get our desired result:

  • Configure CORS rules to allow content to be pulled from cineplex.com

  • Add a step in our CI/CD pipeline to purge the CDN when new code is deployed

Vercel also has the benefit of abstracting creating a CI/CD pipeline from the developer. In Azure devops, it was pretty easy to create a build pipeline that simply runs npm install, npm run build, then a release pipeline that deploys the resulting artifact to our App Service and runs npm run start to start the Next.js server.

At this point, we’ve been able to leverage the major performance-boosting features of Next.js without being tied to Vercel hosting. The only feature we haven’t yet replicated is automatically deploying API endpoints as serverless functions due to the fact that we haven’t yet needed that feature.

As the modernization journey with Cineplex continues, we’ll be looking to increase performance and scalability as much as possible by leveraging the power of serverless functions to replace a single Node.js server running next start.

Hopefully, if you find yourself in a situation where your deployment options are limited, these learnings can help you out. If you'd like the step-by-step instructions on how to create your own Azure/AWS/GCP hosted solution for your Next.js application you can check out my other blog here.

Share

You might also like

Transform your digital products

Talk to us today