This is a moderately configurable template for getting a serverless SvelteKit application quickly deployed to AWS, using Terraform. It's also a bit of a developer toolkit, containing a Dockerfile & docker-compose.yml; local development utility scripts; linting and formatting configurations that may be of convenience. This particular project is configured to use TypeScript, Vitest for unit testing, Playwright for browser testing, uses adapter-node and has a simple "Welcome to SvelteKit" page at the root (i.e., a skeleton SvelteKit application with all the additional options selected when creating a new project from the CLI).
This was inspired by a mix of this post by Sean W. Lawrence, sveltekit-adapter-aws, and my own strange musings.
Feel free to use this however suits; this is deliberately a template so that you can get started with minimal configuration, but equally lets you add/modify/remove components however you fancy (as is how I've been using it for kickstarting my own things).
git init
; make sure you don't have the .git
folder carried over from this template if you cloned it.npm run prepare
to set up the husky pre-commit hook, which uses lint-staged to run appropriate linters/formatters etc. on staged files, and does an npm run check
(svelte-check) on everything Svelte..husky/pre-commit
script..lintstagedrc.js
file. See more here..env.dev.example
file. Environment variables pertaining to the containerised development and deployment processes are documented here. If you want to configure any of them, create a copy called .env.dev
and configure as you like.npm install
here. If you are using the container, that'll be done for you when it starts up.run-local.sh
script with Bash. This will build the Dockerfile
, then cleans up any containers running the old image and does a docker compose up
using the docker-compose.yml
. The container does a sleep infinity
, so this will continue running for as long as the terminal is held open (allowing you to develop in there).cd
into the /home/{SVELTEKIT_PROJECT}
directory (defaults to /home/development
).Dockerfile
directly - for instance, if you want to install additional packages out of the box, etc. The same goes for the docker-compose.yml
.deploy.sh
script. Make sure you've configured any environment variables you want to use - for example the AWS profile or region, etc.infra/lambda-template
(a tiny package that uses an Express server to proxy requests through to a handler - in our case, the built SvelteKit handler.js
file) into the configured build folder, and deploy that to Lambda, fronted by an API Gateway Lambda Proxy, a CloudFront distribution, and an S3 bucket for any static assets.deploy.auto.tfvars
file in the infra/terraform/deploy
folder, so you can destroy infrastructure, run plans etc. directly from the Terraform CLI as usual with the same variables.infra/terraform
folder - it is fairly minimalist as it stands - see here.--auto-approve
flag: This mirrors Terraform's flag of the same name, which skips the manual approval step when running terraform apply
.--no-build
flag: Skips the build step and uses whatever is currently in the specified build folder (default build
). Requires that a build has been done before.There is the option of setting up a custom domain with AWS Route 53 pointing to the generated CloudFront distribution, but it's a little more invested than the rest of the configurations...
.env.dev.example
file for the environment variables, but pertinent to this bit of the configuration are the SVELTEKIT_DOMAIN_NAME
and SVELTEKIT_ROUTE53_HOSTED_ZONE_ID
variables.SVELTEKIT_SUBDOMAIN
environment variable blank, but you can provide a subdomain (or a chain of them) if you like (a "www" subdomain will be added to whatever concatenation of subdomain + domain name you have provided, and the site will be accessible with or without it).If the infrastructure you're provisioning sits in the same AWS account as the AWS Route 53 hosted zone that you want to use, then you can skip this step. However, it's a pretty common use case for people to have their DNS stuff centrally-managed in one account and other bits of infrastructure elsewhere. Therefore, the template allows you to provide the ARN of a role that can be assumed in another account, to manage the hosted zone and AWS Certificate Manager (ACM) certificates. The environment variable to pass this into is SVELTEKIT_ROUTE53_CROSS_ACCOUNT_ROLE_ARN
, and the role in the account with the hosted zone should look something like the following:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetHostedZone",
"route53:ListResourceRecordSets",
"route53:ChangeResourceRecordSets",
"route53:DeleteHostedZone"
],
"Resource": "arn:aws:route53:::hostedzone/*"
},
{
"Effect": "Allow",
"Action": [
"route53:GetChange"
],
"Resource": "arn:aws:route53:::change/*"
},
{
"Effect": "Allow",
"Action": [
"route53:ChangeTagsForResource"
],
"Resource": [
"arn:aws:route53:::hostedzone/*",
"arn:aws:route53:::healthcheck/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:CreateHostedZone",
"ec2:DescribeVpcs",
"route53:ListHostedZones",
"route53:GetHostedZoneCount"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"acm:RequestCertificate",
"acm:GetCertificate",
"acm:AddTagsToCertificate",
"acm:DescribeCertificate",
"acm:ListTagsForCertificate",
"acm:ListCertificates",
"acm:DeleteCertificate",
"acm:UpdateCertificateOptions",
"acm:RemoveTagsFromCertificate"
],
"Resource": "*"
}
]
}
(Yeah, this isn't the world's most tightly locked-down IAM role - you could probably restrict it down to particular ARNs and such when you drop it into your own account.)
The trust policy should look something like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{ACCOUNT_ID_OF_WHERE_YOU'RE_APPLYING_YOUR_INFRASTRUCTURE}:root"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
You can also provide an external ID for assuming the role if you like via the SVELTEKIT_ROUTE53_CROSS_ACCOUNT_ROLE_EXTERNAL_ID
environment variable.
Lastly, your CloudFront distribution will need an ACM certificate to prove you control the domain you want to use. This will need to be provisioned in the account you want your infrastructure in (afaik you can't use a certificate between accounts). You can create one yourself and provide the ARN for it with the SVELTEKIT_ACM_CERTIFICATE_ARN
environment variable, but you will need to do all of the DNS validation and management of the certificate yourself. Alternatively, if you leave that environment variable blank, the Terraform will create one for you - though note that it doesn't keep track of expiry of that certificate (will be after 1 year).
.env
if you deploy from your machine, but you will need an external source for these in a pipeline..gitattributes
file, as well as the .prettierrc
file - feel free to change formatting etc. to whatever suits you.