SST (Serverless Stack) lets you define and deploy full-stack apps on AWS using TypeScript. It abstracts CloudFormation into simple, composable constructs and provides a live development environment.
Why SST?
- TypeScript infra — define AWS resources in TypeScript, not YAML
- Live Lambda — live reload for Lambda functions during dev
- Full-stack — frontend + API + database + auth in one framework
- Components — high-level constructs for common patterns
- Free — open source, you pay only for AWS
Quick Start
npx create-sst@latest my-app
cd my-app
npx sst dev # Live development
npx sst deploy --stage prod # Production deploy
Define Infrastructure (TypeScript)
// sst.config.ts
export default $config({
app(input) {
return {
name: 'my-app',
removal: input.stage === 'prod' ? 'retain' : 'remove',
};
},
async run() {
// Database
const table = new sst.aws.Dynamo('Users', {
fields: { userId: 'string', email: 'string' },
primaryIndex: { hashKey: 'userId' },
globalIndexes: { emailIndex: { hashKey: 'email' } },
});
// API
const api = new sst.aws.ApiGatewayV2('Api');
api.route('GET /users', 'packages/functions/src/users.list');
api.route('GET /users/{id}', 'packages/functions/src/users.get');
api.route('POST /users', 'packages/functions/src/users.create');
// Link resources
new sst.aws.Function('CreateUser', {
handler: 'packages/functions/src/users.create',
link: [table],
});
// Frontend
const site = new sst.aws.Nextjs('Web', {
link: [api],
});
return { url: site.url, api: api.url };
},
});
Lambda Functions
// packages/functions/src/users.ts
import { Resource } from 'sst';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, PutCommand, GetCommand, ScanCommand } from '@aws-sdk/lib-dynamodb';
const ddb = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export async function list() {
const result = await ddb.send(new ScanCommand({
TableName: Resource.Users.name,
}));
return { statusCode: 200, body: JSON.stringify(result.Items) };
}
export async function get(event: any) {
const result = await ddb.send(new GetCommand({
TableName: Resource.Users.name,
Key: { userId: event.pathParameters.id },
}));
return { statusCode: 200, body: JSON.stringify(result.Item) };
}
export async function create(event: any) {
const body = JSON.parse(event.body);
await ddb.send(new PutCommand({
TableName: Resource.Users.name,
Item: { userId: crypto.randomUUID(), ...body },
}));
return { statusCode: 201, body: JSON.stringify({ success: true }) };
}
Components
// Cron job
new sst.aws.Cron('DailyReport', {
schedule: 'rate(1 day)',
job: 'packages/functions/src/report.handler',
});
// Queue
const queue = new sst.aws.Queue('EmailQueue');
queue.subscribe('packages/functions/src/email.handler');
// Bucket
const bucket = new sst.aws.Bucket('Uploads');
bucket.subscribe('packages/functions/src/process.handler', {
events: ['object_created'],
});
// Auth
const auth = new sst.aws.Auth('Auth', {
authenticator: 'packages/functions/src/auth.handler',
});
Key Features
| Feature | Details |
|---|---|
| Language | TypeScript |
| Cloud | AWS |
| Live dev | Live Lambda for instant feedback |
| Components | API, Database, Queue, Cron, Auth, etc. |
| Frameworks | Next.js, Remix, Astro, SvelteKit |
| Deploys | ~30 seconds (incremental) |
Resources
Building on AWS? Check my Apify actors or email spinov001@gmail.com.
Top comments (0)