RFC: state of Serverless Next.js and next steps
See original GitHub issueHi all!
I hope you are having a great weekend. I just wanted to take some time to give some updates on the current state of Serverless Next.js. This is a long post - TL;DR on bottom if you want. Ever since I’ve started using this early this year, and contributing just a few months back, we as a community have accomplished, as of version 1.18 or 1.19 alpha:
- Stability improvements: for example, we added multiple end-to-end tests that deploy a real Lambda@Edge for both the current-minor and previous-minor Next.js versions, pinned dependencies, enabled security updates (automated dependency updates are a WIP via Renovate), and added a bunch more unit test coverage for the handler code.
- Build/deploy and configuration improvements: thanks to all the bug reports and suggestions, we’ve merged many improvements to configuring CloudFront inputs and other
serverless.yml
outputs, decoupling build step from the deploy step, etc. - Feature parity: except for the recently released Next.js 10 features, some more involved features (like revalidate on SSG), and a few miscellaneous bugs or quirks, the majority of Next.js 9.x features should be implemented and fairly stable and well-tested.
…and more. Thank you for all your support and contributions, and for helping us test and report bugs with the latest alpha versions!
That being said, we’ve also noticed these two biggest pain points:
- Lambda@Edge and CloudFront are highly coupled with the core code of routing and rendering the correct pages. As an end user of this package, you may not notice it, but this actually makes it harder to support new platforms, such as Lambda, Cloudflare, GCP, Azure, etc. As a maintainer, it also makes it hard to separate testing the platform integration vs. testing the core code.
- Infrastructure management has been difficult and sometimes has inconsistent results, as there is no first-class state management like a proper infrastructure-as-code (IaC) tool. The reason for this is that the Serverless Components we use (aws-cloudfront, domain, etc.) weren’t well maintained and interfaced with the AWS SDK directly and do not manage state except for saving the Lambda function name, CloudFront distribution ID, etc (in the
.serverless
directory).
This brings us to the next set of challenges:
- Decoupling and modularizing the runtime code itself so it’s not tied Lambda@Edge. This will help us in separating concerns to the respective packages. Fortunately, we have Rollup.js or other bundlers which can largely help with this. I propose the following:
- Core Next.js code: this is the core routing and rendering logic, all specific to Next.js rendering of SSR, SSG pages and doing non-dynamic, dynamic routing.
- Optional request/response middleware: any additional runtime code you’d like to run before/after the core serverless code is run. For example, you could use this to do basic authentication, log additional metrics, etc. This doesn’t really belong to the core routing code. We could provide a few essential first-party middleware, the community can contribute additional middleware to the package, another package, or use their own.
- Bundler: bundles the core Next.js code together with any included middleware, including custom middleware.
- Platform plugins: these plugins are responsible for building and deploying the code to a specific platform. For example, this can be Lambda@Edge, Lambda, Cloudflare, etc. Its responsibility is to take the bundled core code + middleware and further bundle that with lightweight platform compatibility layers that interface with the core. It can also perform any further optimizations as needed. For example, for Lambda@Edge, this will involve the CloudFront event. As part of this, we may also plan to reduce the Lambda@Edge handlers into a single origin request handler to simplify the architecture and even improve performance by reducing cold start + CloudFront + S3 origin + Lambda complexity.
In essence, everything except for the platform plugins should be platform-agnostic.
-
Properly decoupling build and deploy steps, and making it more configurable: much of this is already done, as you can just build only
.serverless_nextjs
outputs using this component, and actually deploy using your own IaC tools - although there is no first-party implementation of CDK yet. This brings us to the last point: -
Proper infrastructure-as-code and state management. We’ve seen that our use of AWS SDK means we need to keep updating deployment code to support new features. There is also no proper state management. Fortunately, there are tools like CDK, Terraform, Pulumi etc. that have already already solved these issues, by storing state remotely (e.g in Terraform, you can store it in Terraform, S3, etc).
- Explore the use of CDK / CDK for Terraform / Pulumi. We are leaning towards CDK and CDK for Terraform, since I am familiar with Terraform and it also seems to have the most providers and gives more flexibility. Also, a deployment has two phases: provisioning static infrastructure, like CloudFront, Lambda@Edge, and S3, and uploading/deploying new code and assets, so this lends itself well.
-
Serverless Components GA upgrade: with all the above in mind, we are still planning to upgrade to Serverless Components GA as part of this. The plan is for some of the above refactoring to make this much easier.
We hope to incorporate at least some of these into the next major release (v2), I am hoping sometime in Q1 2021. Please share any thoughts or feedback you may have. We could also definitely use some help on some of this (after or in parallel to modularization), especially on supporting new platforms other than Lambda@Edge, since it’s mostly @danielcondemarin and me maintaining this package.
I will update this post as I get more feedback. Thank you for reading!
FYI: @danielcondemarin
TL;DR: for v2 release, we are planning to modularize and decouple the component from Lambda@Edge, make it more platform-agnostic and support more platform deployments, and improve pain points related to infrastructure management. In addition, we will plan to upgrade to Serverless Components GA. We would love feedback or comments to help us improve.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:66
- Comments:11 (1 by maintainers)
Top GitHub Comments
@chancity sure, that would be great, feel free to ping @danielcondemarin if you’d like to be added to the Slack to discuss. We’d definitely love some help
@JordanLao we do want to support Lambda next, though first as mentioned we want to:
(1) involves quite a bit of refactoring, so probably best to be done by a core contributor. If you would like to help with (2), let me know and we can add you to the Slack. Basically for (2) you could actually start on the deployment logic (setting up Lambda, uploading to S3, API Gateway, CloudFront for assets etc.) assuming that the build outputs look something similar to the existing
.serverless_nextjs
folder (withdefault-lambda, api-lambda, assets
directories, though of course the handler will remove CloudFront specific logic).As for Fastly, I don’t believe they support JavaScript yet, unless something changed? See: https://www.fastly.com/blog/why-edge-compute-does-not-yet-support-javascript. They also don’t use Node.js nor V8 isolates (like Cloudflare Workers) so it would even trickier, I imagine. I would say that it would be easier to add Cloudflare Workers support - as FAB project has already done so to some extent.
I will close this for now since I think the future plans are quite clear: Currently work is being done to support Lambda/APIGW and help reduce complexity (trying to remove origin response handler, etc.), and after we can start looking at other platforms.