This repository is an example for the blog post Deploying Sveltekit to AWS Lambda.
I had a hard time using the sveltekit-adapter-aws and services like Elastic Beanstalk, ECS, and CloudFlare Pages. So I created a minimal example of deploying Sveltekit to AWS Lambda using the CDK.
nvm install 18 && nvm use 18
if using NVMnpm create svelte@latest <app-name>
npx cdk bootstrap
pre-build-lambda-assets
mkdir pre-build-lambda-assets
package.json
file in the new directory. This tells the Node runtime that we're using the module type, which Svelte's node adapter uses to output the assets. It also installs the only two dependencies we'll need, aws-serverless-express
to make the server Lambda-friendly and polka
as a minimal web server.Note: you can replace
polka
withexpress
or your Node server of choice. I just chosepolka
since it was what was used in the index.js file that Svelte outputs in the build directory and make minor tweaks to get it working with Lambda.
./pre-build-lambda-assets/package.json
{
"type": "module",
"dependencies": {
"aws-serverless-express": "^3.4.0",
"polka": "^0.5.2"
}
}
Run npm install
in this folder to generate a package-lock.json
. And then delete the node_modules
folder that it generated in this folder. Our script will install a fresh node_modules
in the build
directory when we deploy rather than copying these.
Create a lambda handler file. This creates a basic web server just like the original Sveltekit node adapter, and then wraps it with the aws-serverless-express
functions. And finally, it passes in the event and context from the Lambda request.
./pre-build-lambda-assets/lambda-handler.js
import { createServer, proxy } from 'aws-serverless-express';
import polka from 'polka';
import { handler as svelteHandler } from './handler.js';
const app = polka().use(svelteHandler);
const server = createServer(app.handler);
export const handler = (event, context) => {
proxy(server, event, context);
};
./infra/deploy.ts
import { resolve } from 'path';
import * as cdk from 'aws-cdk-lib';
import type { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
class SveltekitDemo extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
const handler = new lambda.Function(this, 'SveltekitHandler', {
code: lambda.Code.fromAsset(resolve(process.cwd(), 'build')),
handler: 'lambda-handler.handler',
runtime: lambda.Runtime.NODEJS_18_X
});
const api = new apigateway.LambdaRestApi(this, 'API', { handler });
new cdk.CfnOutput(this, 'APIDomain', { value: api.domainName?.domainName || '' });
}
}
const app = new cdk.App();
new SveltekitDemo(app, 'SveltekitDemo');
app.synth();
./deploy.sh
#! /usr/bin/env bash
npm run build
cp -r ./infra/pre-build-lambda-assets/. ./build/
cd build
npm ci --omit dev
cd ../
npx cdk deploy
chmod +x ./deploy.sh
npm install @sveltejs/adapter-node --save-dev
svelte.config.js
configuration file to use the node adapter./svelte.config.js
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter()
}
};
export default config;
./deploy.sh
APIDomain
We created the following:
Logical next steps are to add a CloudFront distrbution in front of API Gateway to cache requests for faster performance and adding an SSL certificate and custom domain to the distribution.
Happy coding! SL