Skip to main content

What is SST

SST is a framework that makes it easy to build modern full-stack applications on AWS.

Deploy a serverless Next.js, Remix, Astro, or Solid site to your AWS account and add any backend feature to it.


Frontend

Start by defining, in code, the frontend you are using. SST supports the following.


Next.js

new NextjsSite(stack, "site", {
path: "web",
customDomain: "my-next-app.com",
});

Behind the scenes, NextjsSite will create the infrastructure to host your serverless Next.js app on AWS. Including Lambda functions for SSR, edge functions for Middleware, a CDN, and an S3 bucket for static assets.


Remix

Similarly there's RemixSite for Remix.

new RemixSite(stack, "site", {
path: "web",
customDomain: "my-remix-app.com",
});

Astro

Or the AstroSite for Astro.

new AstroSite(stack, "site", {
path: "web",
customDomain: "my-astro-app.com",
});

Solid

And the SolidStartSite for Solid.

new SolidStartSite(stack, "site", {
path: "web",
customDomain: "my-solid-app.com",
});

Static sites

There's also the StaticSite for any static site builder.

new StaticSite(stack, "site", {
path: "web",
buildOutput: "dist",
buildCommand: "npm run build",
customDomain: "my-static-site.com",
});

Just specify the build command and point to where the output is generated.


Infrastructure

The above snippets are a way of defining the features of your application in code. You can define any feature of your application, not just the frontend.

You can add backend features like APIs, databases, cron jobs, and more. All without ever using the AWS Console.

Let's look at it in detail.


Constructs

These snippets are called Constructs. They are TypeScript or JavaScript classes, where each class corresponds to a feature that can be configured through its props.

const site = new NextjsSite(stack, "site", {
/** props **/
});

We recommend using TypeScript because it allows for full type safety while configuring your application.


Stacks

Constructs are grouped into stacks. They allow you to organize the infrastructure in your application.

stacks/Web.ts
export function Web({ stack }: StackContext) {
const site = new NextjsSite(stack, "site");
}

Each stack is just a function that creates a set of constructs.


App

Finally, you add all your stacks to your app in the sst.config.ts.

sst.config.ts
export default {
config(input) {
return {
name: "my-sst-app",
region: "us-east-1",
}
},
stacks(app) {
app.stack(Database).stack(Api).stack(Web);
},
} satisfies SSTConfig;

Here we are also specifying a name for our app and the AWS region it'll be deployed to.

Now let's look at how you can add the backend for your app with these constructs.


Backend

SST has constructs for most backend features. And you can even use any AWS service in your app.


APIs

For example, with the Api construct you can define an API in a few lines.

new Api(stack, "API", {
routes: {
"GET /notes": "services/list.main",
"POST /notes": "services/create.main",
},
});

Behind the scenes, this creates a serverless API using Amazon API Gateway, where each route points to a Lambda function.


Functions

So when a user hits the /notes route in your API.

"GET /notes": "services/list.main"

The main function in services/list.ts gets executed. The API then responds with what's returned.

services/list.ts
export async function main() {
return {
statusCode: 200,
body: JSON.stringify([
/** list of notes **/
]),
};
}

Your functions can be in TypeScript, JavaScript, Python, Golang, Java, or C#.


Databases

You can add a serverless database to your app. Here the RDS construct configures a new Amazon RDS serverless PostgreSQL cluster.

new RDS(stack, "notesDb", {
engine: "postgresql11.13",
defaultDatabaseName: "main",
migrations: "services/migrations",
});

In addition to SQL databases, SST also supports Amazon DynamoDB, a NoSQL serverless database.


Cron jobs

You can add cron jobs to your application with a few lines. Here's a cron job that calls a function every minute.

new Cron(stack, "cron", {
schedule: "rate(1 minute)",
job: "services/cronjob.main",
});

SST also has constructs for Auth, Queues, Pub/Sub, Data Streams, and more.


All AWS services

Aside from the features that SST's constructs support, you can add any AWS service to your app. This is because SST is built on top of AWS CDK and you can use any CDK construct in SST.

Here we are defining an Amazon ECS cluster with an AWS CDK construct.

import * as ecs from "aws-cdk-lib/aws-ecs";

const cluster = new ecs.Cluster(stack, "Cluster", {
vpc,
});

This ensures that as your app grows, you'll be able to add any feature you need.


Connecting everything

Once you've added a couple of features, SST can help you connect them together. This is great because you won't need to hardcode anything in your app.


In the frontend

For example, you can grab the endpoint of your API and pass it to Next.js as an environment variable.

const api = new Api(/* ... */);

new NextjsSite(stack, "site", {
// ...
environment: {
API_URL: api.url,
},
});

You can then connect to your API in Next.js without hardcoding the URL.

web/pages/index.tsx
export async function getStaticProps() {
const notes = await fetch(process.env.API_URL);
// ...
}

In the backend

Similarly, you can allow your backend functions to securely connect to your infrastructure, through a concept we call Resource Binding. For example, you can bind the PostgreSQL database to the API.

const rds = new RDS(stack, "notesDb" /* ... */);
const api = new Api(/* ... */);

api.bind([rds]);

Now the functions in your API will have type safe access to your database.

services/list.ts
import { RDS } from "sst/node/rds";

export async function main() {
new ExecuteStatementCommand({
sql: "select * from notes",
secretArn: RDS.notesDb.secretArn,
resourceArn: RDS.notesDb.clusterArn,
database: RDS.notesDb.defaultDatabaseName,
});
}

Behind the scenes SST also adds the required permissions, so only your API has access to the database.


Project structure

We've looked at a couple of different types of files. Let's take a step back and see what an SST app looks like in practice.

SST applications are monorepo by default.

my-sst-app
├─ sst.config.ts
├─ package.json
├─ packages
│  ├─ frontend
│  └─ functions
├─ stacks

Where the packages/frontend/ directory is your frontend, packages/functions/ is the backend, and stacks/ has your infrastructure definitions. For the frontend of your application, SST lets you deploy Next.js and Remix apps. Or any static website.

Here for example, we are defining a Vite static site using the StaticSite construct.

new StaticSite(this, "site", {
path: "packages/frontend",
buildCommand: "npm run build",
buildOutput: "dist",
customDomain: "my-sst-app.com",
environment: {
VITE_API_URL: api.url,
},
});

Behind the scenes, this creates a static website powered by Amazon S3 and serves it through Amazon CloudFront, a CDN.


Connect to the API

SST makes it easy to connect your frontend to your API by letting you share config between constructs.

For example, you can grab the API endpoint from the API construct and pass it to our frontend as an environment variable.

const api = new Api(/* ... */);

new StaticSite(this, "site", {
// ...
environment: {
VITE_API_URL: api.url,
},
});

With SST, we don't need to hardcode our backend config in the frontend.


SST CLI

To help with building and deploying your app, SST comes with a CLI.


Local dev

The sst dev command starts a local development environment called Live Lambda, that connects directly to AWS. Letting you set breakpoints and test your functions locally.

npx sst dev

Now you can start your frontend with the sst env command. It'll connect your frontend to the backend by loading all the environment variables.

cd web
sst env "next dev"

With this you can make changes to your backend on AWS, and see them directly in your frontend!


SST Console

The sst dev CLI also powers a web based dashboard called the SST Console.

SST Console homescreen

With the Console you can view and interact with your application in real-time. You can manually invoke functions, view logs, replay invocations, and do things like query your database and run migrations.


Deployment

To deploy your application to AWS, you use the sst deploy command. It uses your local IAM credentials and deploys to your AWS account.

npx sst deploy

Since everything in your app is connected, this single command is all you need. Once complete, it'll print out your app's URL!

Outputs:
ApiEndpoint: https://ck198mfop1.execute-api.us-east-1.amazonaws.com
SiteUrl: https://my-next-app.com

Behind the scenes, it compiles the constructs to AWS CloudFormation, packages your frontend assets and functions, uploads it to AWS, and creates your app's infrastructure.


Environments

The sst deploy command can also deploy your app to a specific stage or environment. This lets you create separate environments for development, production, pull-requests, or branches.

# Deploy to dev
npx sst deploy --stage dev

# Deploy to production
npx sst deploy --stage prod

You can use this in your GitHub Actions workflow to generate pull-request based environments.

Or, you can get automatic preview environments with SEED, a service built by the SST team.


Starters

To create your first SST app you can use one of our starters with the create-sst CLI.

npm create sst@latest

This will set you up with a full-stack TypeScript app with a React frontend, GraphQL API, and a PostgreSQL database.

However, if you are a more advanced user, you can pick one of our minimal templates and use our constructs to build the type of app you need.


To get started with SST, check out our tutorial.