Whenever deploying toy Next.js applications, I’ve always defaulted to Vercel, however, at some point I was tasked with deploying Next.js in AWS. Next.js documentation mentions AWS Amplify as one of the alternatives for Next.js hosting, so it looks like its easy!
Deploying a Next.js app on AWS Amplify is easily done using the console, you just link a git repository to your Amplify project and that is pretty much it, you might need to adjust some of the IAM Roles that your service account has. (This is one of the hidden gotchas, I think I eventually found it being mentioned somewhere, but not exactly the easiest find)
However, you’ll eventually hit some of the rough spots that AWS Amplify has:
- Can’t seem to use your roles for your API routes or server side Next.js stuff, you’ll need to manually add extra environment variables, plus Amplify wont allow for the standard environment variable names!!!!!. (Vercel has better support for this! You just add the env variables with the standard
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYand don’t need to add them to the app itself, your SDK will use the default credentials provider to pick them up) - Can’t deploy your Next.js server side to a VPC, to enable use cases such as connecting to RDS without going through the internet.
Side note: Vercel offers VPC peering on the enterprise plans, but those are not cheap.
Our Enterprise Product, on average, runs low-to-mid four figures per month with a 12-month upfront contract.
The solution so far
I’m testing OpenNext, which is an effort led by the SST team. I can’t yet tell if it is better than Amplify, but it was okay to understand and deploy for the first time, however there are some gotchas/bugs/documentation flaws.
- The NextjsSite construct documentation page has an example on how to deploy your Next.js app in a VPC, however, it seems to lack detail on some of the code that is provided:
import { Vpc, SubnetType } from "aws-cdk-lib/aws-ec2";
// Create a VPC
const vpc = new Vpc(stack, "myVPC");
// Alternatively use an existing VPC
const vpc = Vpc.fromLookup(stack, "myVPC", { ... });
const vpcSubnets = {
/** You might want to understand what is considered what by the CDK
https://github.com/aws/aws-cdk/blob/ee3d41e674bc6b02cabd986de92075350017209b/packages/aws-cdk/lib/context-providers/vpcs.ts#L72-L78 */
subnetType: SubnetType.PRIVATE_WITH_EGRESS,
};
new NextjsSite(stack, "Site", {
path: "my-next-app/",
cdk: {
server: {
vpc,
vpcSubnets,
},
/** I think they should mention if one really needs/wants the revalidation function in a VPC*/
revalidation: {
vpc,
vpcSubnets,
// This object seems to be missing `allowPublicSubnets` property
}
}
});