Svelte Kit SSR + AWS Lambda

James Bray
29 Aug 2023

With Svelte Kit edging ever closer to release I wanted to test it out and move this blog over from a single page app, to a been rendered on server as an isomorphic app.

Why is SSR making a comeback?

There was a time when all websites were rendered on a server. However, since the rise of client-side Javascript frameworks and more interactive web applications and SPA, rendering your app on a server had fallen out of fashion in recent years. However, with the introduction of frameworks like Svelte Kit and plugins like ReactDOMServer a new type of web app, Isomorphic, are been developed.

Isomorphic web apps combine all the benefits of SSR (Improved SEO, social sharing ability, short TTI, etc.) with all the advantages of SPA's (Core app code can be downloaded once and reused, rapid development speed, etc.).

My setup

To generate the server Lambda that is compatible with Lambda Proxy, I wrote this adapter package. The server itself is very simple, with minimal logic to adapt the lambda proxy request and response to an object accepted by the render() function generated as part of the Svelte Kit build process. Also included is a set of shims for core Svelte functions, for these I'm just using the default Svelte libs.

To deploy the application I choose to use serverless framework.

Example Serverless config snippet
service: xxxx

provider:
  name: aws
  runtime: nodejs18.x

package:
  individually: true
  exclude:
    - ./**
  include:
    - build/server/**

functions:
  svelte:
    handler: build/server/serverless.handler
    memorySize: 256
    timeout: 15
    url: true

resources: 
   CloudFront:
   Type: 'AWS::CloudFront::Distribution'
    Properties:
     DistributionConfig: 
       Origins:
            -
              DomainName: > 
!Select [2,!Split ["/",!GetAtt ["SvelteLambdaFunctionUrl","FunctionUrl"]]]
 ...

An overview of the setup used for this blog can be seen below.

Setup Diagram

To improve page speed I have a high max-age cache on all pages and even more so on the backend API, then, when the state of the blog changes I trigger an invalidation of the appropriate paths in Cloudfront to server the new content to users.

Static Assets and Pre-rendered Pages

To help speed up the serving on uncached static assets and pre-rendered pages and allow for static assets larger than a few megabytes I use S3 to serve them. To achieve this, as part of the build process all static and precompiled files are uploaded to S3 and a manifest of those files is created and incorporated into a Lambda@Edge function that performs an origin rewrite for all files hosted in S3.