Next.Js Deployment/Hosting Findings
Introduction
The TSS frontend app was originally built using create-react-app (CRA), which, although popular, is now deprecated and lacks support for server-side rendering. To enhance flexibility, the app was wrapped in Next.js; however, TSS has not yet fully taken advantage of the latest features available in React and Next.js. Therefore, it’s essential we investigated the optimal deployment or hosting setup to ensure we can effectively utilize these advancements moving forward.
Deployment Hosting Platforms Investigated
AWS Lambda
AWS Amplify Hosting
AWS Elastic Container Service
Vercel
Acceptance Criteria
The investigation used the following acceptance criteria:
Cost
Complexity
Ease of deployment
Performance
Resilience
Scalability
Securely accessing private resource (e.g. internal API endpoints)
Architecture
Findings
AWS Lambda (ticket)
Using AWS Lambda allows developers to run code without the need for server management, paying only for compute time used. This serverless model means there are no costs incurred when the code isn’t running, which can lead to "cold starts" when new requests trigger a dormant function.
However, deploying Next.js on AWS Lambda presents challenges due to its file generation process, which can create outputs exceeding Lambda's 250MB size limit. This necessitates the use of specialized frameworks to facilitate deployment.
While frameworks like SST and AWS SAM can be useful, they often require adjustments to handle Next.js’s file size constraints. To address these limitations, I found that using a combination of SAM and Docker approach with the AWS Lambda Web Adapter is beneficial.
The AWS Web adapter enables the deployment of existing Next.js applications as Lambda functions without major code changes. It also acts as a proxy, reducing cold start times, although the first execution can still result in longer cold starts.
AWS Elastic Container Service ECS (Ticket)
I explored deploying the NextJS application on AWS Elastic Container Service (ECS), a managed service for orchestrating containerized applications. Deployment involves containerizing the application, pushing it to Amazon ECR, and defining a task definition template alongside service configurations and IAM roles.
Using Terraform, I deployed the sample application with Fargate, allocating 256 CPU units and 512 MB memory, and configured autoscaling with a desired task count of 3.
To test for performance I used K6 to load test the deployed code:
Single Task: 100% success for one endpoint, 99% for the API. Response times exceeded 500ms for four requests, with CPU utilization over 60%.
Three Tasks: All requests responded in under 500ms with no failures, demonstrating high availability and fault tolerance with effective autoscaling.
The results indicate that AWS ECS can maintain performance and resilience, particularly under higher load scenarios.
AWS Amplify Hosting (Ticket)
The Next.js Sample application was also deployed using AWS Amplify Hosting, a fully managed CI/CD and hosting service suitable for static and server-side rendered apps.
Deployment Steps:
Connect Repository: I connected the repository containing the Next.js code to AWS Amplify and authenticated the connection.
Configure Application: I specified an application name and selected the branch to deploy from. Amplify supports both monorepo and multibranch builds, which provided flexibility for managing different environments.
Automatic Setup: Amplify automatically detected that I was using Next.js, configuring the necessary build settings and running
yarn install
to install dependencies.CI/CD Integration: I set up hooks with the repository, enabling Amplify to trigger a new build for every merge request, streamlining the CI/CD process.
Hosting Features: Amplify has hosting features, including custom domains and redirects, which can be configured too using the Amplify UI or CLI tools for a seamless integration.
Testing: AWS Amplify also offer testing capabilities to run Cypress tests, this can help ensure application quality during deployment process.
Overall, deploying Next.js on AWS Amplify was efficient and user-friendly, leveraging its managed services and automated features to ensure a reliable deployment. The artifact size limit of 5GB which was adequate for this implementation.
Vercel Hosting (Ticket)
Vercel is a developer-focused platform that simplifies building and deploying web apps, especially for Next.js, which it created. Deployment is straightforward: connect the code repository, click deploy, and Vercel handles the rest, including generating deployment template.
Key Features:
Native support for SSR, caching, and monitoring.
Speed insights can be enabled with
npm install @vercel/speed-insights
.Analytics support includes 2,500 events/month on the hobby plan and 25,000 on the pro plan.
Deployment steps
Created a Vercel account and added a new project.
Connected my Next.js repository and deployed.
Received an auto-generated
*.vercel.app
domain, which can be customized.
Billing: Plans include Hobby (free), Pro ($20/month per collaborator), and Enterprise (with additional benefits).
Billing: Vercel offers three plans—Hobby (free), Pro ($20/month per collaborator), and Enterprise (with enhanced benefits).
| LAMBDA | ECS | AMPLIFY | VERCEL | |
---|---|---|---|---|---|
1 | COST |
|
|
| The cost for the pro plan is $20 per collaborator. Additional costs include compute expenses, edge request fees, storage, data transfer, monitoring, and other related charges. |
2 | COMPLEXITY |
|
|
| Relatively easy for UI based operations. All Vercel operations can be done Using the UI. There is also a terraform Provider for Vercel for IAC configuration |
3 | EASE OF DEPLOYMENT | When the framework for Deployment of the Next.Js project is decided, deployment can be relatively easy (SAM + Docker in our case). Also CICD can simplify deployment further further. | Deployment is simple and easy with IAC and CICD. Require experience and Expertise with the required tools. | Deployment is very easy and simple with Amplify.
| Vercel deployment is easy and straightforward. |
4 | PERFORMANCE/SCALABILITY | Performance: Good Performance, though there is cold start, it was almost unnoticeable. Scalability:
| ECS is highly scalable, as it integrates with Autoscaling to dynamically adjust container count based on traffic. Highly performant as Fargates helps to achieve this autoscaling without managing servers. | Amplify has high performance as it can handle sudden traffic spike and scale horizontally, its underlying resources are serverless. For load test; same scenario as the lambda’s all request was successful.
| Vercel is a serverless Platform and hence boast of great scalability and performance. There are other features that can be integrated to applications from Vercel UI, such as WAF, Caching, DB, etc. |
5 | RESILIENCE | Highly resilient with built in redundancy, high availability and good error handling. Lambda also has native integration with CloudWatch. | ECS ensures high availability and integrates with Load Balancers (ALB or NLB) to distribute loads across auto scaled tasks. Fargate is highly resilient with AWS managing the infrastructure, it abstract fault tolerance. | Highly resilient, with its underlying AWS Infra, it benefits from AWS’s Global network, redundancy and failover mechanisms. It also has native integration with CloudWatch. | Vercel's Edge Network is designed with high availability and fault tolerance in mind Also Vercels resources are backed by AWS cloud platform, hence are resilient. they can scale with user base. It also has monitoring and analytic capability to measure performance and detect issues in time. |
6 | INTERNAL API ACCESS | Lambda in VPC mode can access Private internal endpoints and resources securely. | With ECS we can easily access internal API. ECS offers service discovery and Networking capabilities(including VPC, subnets and security groups) to handle internal API communication. | Amplify do not have VPC integration and hence not suitable for accessing internal API like private backend URL or database.
| Vercel do not have a way or function to integrate with internal APIs running on different environments for Pro or hobby plans.
|
Recommendations
This recommendation is based on services that meets the Acceptance Criteria
AWS Elastic Container service:
In my investigation of AWS ECS, I observed that while loading the web page in a browser is fast and the cold start issue is not noticeable during typical usage, it does become apparent during K6 load testing with a small number of users and a simple app with two routes. For user-facing applications, I generally prefer platforms that minimize or eliminate cold starts.
ECS is particularly well-suited for predictable use cases, such as trainee frontend applications. Given that my final output is a Docker container, I recommend using ECS for hosting the Next.js frontend. Leveraging the serverless capabilities of Fargate, ECS serves as a robust container orchestration platform that effectively manages container-based applications.
One of the key advantages of ECS is its greater control over resource allocation compared to AWS Lambda, allowing us to optimize costs for long-running tasks and high-throughput applications. However, it’s important to note that ECS can be more expensive than Lambda, although Lambda's costs can escalate rapidly under high usage scenarios.
AWS LAMBDA
AWS Lambda operates on a pay-per-use basis, charging only for compute time, which is ideal for serverless Next.js applications with variable traffic and no upfront costs for idle capacity. Lambda can scale to Zero when the function is not serving request hence saving cost. from a cost perspective Lambda is a cheaper option compared to ECS as shown in the Pricing calculator cost comparison.
Lambda automatically scale to handle varying traffic loads, efficiently managing sudden spikes without the need for pre-provisioning resources.
With AWS SAM, Docker and AWS Lambda web adaptor, deployment and future code update can be seamless and easy.
Trade-offs in Choosing AWS Lambda vs. ECS
AWS Lambda: The trade-off is reduced control over underlying resources and less predictability in costs, especially during peak usage.
AWS ECS: The primary trade-off is higher costs, as it can be more expensive compared to Lambda, because of the resources it hooks with at the background. E.g. Load Balancer
References and documentation
Slack: https://hee-nhs-tis.slack.com/
Jira issues: https://hee-tis.atlassian.net/issues/?filter=14213