home / skills / gilbertopsantosjr / fullstacknextjs / sst-infra

sst-infra skill

/skills/sst-infra

This skill guides AWS serverless infrastructure with SST v3, helping you deploy, manage secrets, and configure CI/CD for Next.js apps.

npx playbooks add skill gilbertopsantosjr/fullstacknextjs --skill sst-infra

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.1 KB
---
name: sst-infra
description: Guide for AWS serverless infrastructure using SST v3 (Serverless Stack). Use when configuring deployment, creating stacks, managing secrets, setting up CI/CD, or deploying Next.js applications to AWS Lambda with DynamoDB.
---

# SST v3 Infrastructure

## Project Structure

```
project/
├── sst.config.ts          # Main SST config
├── stacks/
│   ├── dynamodb.ts        # Database stack
│   ├── nextjs.ts          # Next.js deployment
│   └── environment.ts     # Environment config
└── open-next.config.ts    # Lambda streaming config
```

## Main Config

```typescript
// sst.config.ts
export default $config({
  app(input) {
    return {
      name: 'my-app',
      removal: input?.stage === 'prod' ? 'retain' : 'remove',
      protect: ['prod'].includes(input?.stage ?? ''),
      home: 'aws',
      providers: { aws: { region: 'us-east-1' } },
    }
  },
  async run() {
    const { table } = await import('./stacks/dynamodb')
    const { site } = await import('./stacks/nextjs')
    return { url: site.url, tableName: table.name }
  },
})
```

## DynamoDB Stack

```typescript
// stacks/dynamodb.ts
export const table = new sst.aws.Dynamo('Table', {
  fields: {
    pk: 'string', sk: 'string',
    gsi1pk: 'string', gsi1sk: 'string',
  },
  primaryIndex: { hashKey: 'pk', rangeKey: 'sk' },
  globalIndexes: {
    gsi1: { hashKey: 'gsi1pk', rangeKey: 'gsi1sk' },
  },
  transform: {
    table: (args) => { args.billingMode = 'PAY_PER_REQUEST' },
  },
})
```

## Next.js Stack

```typescript
// stacks/nextjs.ts
import { table } from './dynamodb'

export const site = new sst.aws.Nextjs('Site', {
  path: 'apps/web',
  link: [table],
  environment: {
    TABLE_NAME: table.name,
  },
  domain: {
    name: `${$app.stage === 'prod' ? '' : `${$app.stage}.`}myapp.com`,
    dns: sst.aws.dns({ zone: 'myapp.com' }),
  },
})
```

## OpenNext Config

```typescript
// open-next.config.ts
import type { OpenNextConfig } from 'open-next/types/open-next'

const config: OpenNextConfig = {
  default: {
    override: { wrapper: 'aws-lambda-streaming' },
  },
}
export default config
```

## Commands

```bash
# Development (local Lambda)
npx sst dev --stage dev

# Deploy
npx sst deploy --stage dev
npx sst deploy --stage prod

# Remove
npx sst remove --stage dev

# Outputs
npx sst outputs --stage dev

# Secrets
npx sst secret set AUTH_SECRET "value" --stage dev
npx sst secret list --stage dev
```

## Environment Stages

| Stage | Domain | Protection | Removal |
|-------|--------|------------|---------|
| dev | dev.app.com | No | Remove |
| test | test.app.com | No | Remove |
| prod | app.com | Yes | Retain |

## CI/CD (GitHub Actions)

```yaml
# .github/workflows/deploy.yml
name: Deploy
on:
  workflow_dispatch:
    inputs:
      stage:
        type: choice
        options: [dev, test, prod]

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
      - uses: actions/setup-node@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1
      - run: pnpm install --frozen-lockfile
      - run: npx sst deploy --stage ${{ inputs.stage }}
```

## Route Protection (proxy.ts)

```typescript
// src/proxy.ts
import { NextRequest, NextResponse } from 'next/server'
import { authServer } from '@saas4dev/auth'

const protectedRoutes = ['/dashboard', '/settings']

export async function proxy(request: NextRequest) {
  const { pathname } = request.nextUrl
  const isProtected = protectedRoutes.some(r => pathname.startsWith(r))

  const session = await authServer.api.getSession({
    headers: await headers(),
  })

  if (isProtected && !session) {
    const url = new URL('/sign-in', request.url)
    url.searchParams.set('redirect', pathname)
    return NextResponse.redirect(url)
  }
  return NextResponse.next()
}
```

## Local Development

```bash
# DynamoDB Local
docker run -p 8000:8000 amazon/dynamodb-local

# Environment
TABLE_NAME=dev-Table
DYNAMODB_LOCAL=true
```

Overview

This skill guides building and deploying AWS serverless infrastructure using SST v3 (Serverless Stack). It focuses on configuring stacks for DynamoDB, deploying Next.js to Lambda with streaming, environment stages, secrets management, and CI/CD automation. The goal is repeatable, stage-aware deployments for production and non-production environments.

How this skill works

It defines reusable stacks: a DynamoDB table with primary and global indexes and a Next.js site deployed to Lambda with environment bindings and domain configuration. OpenNext is configured for Lambda streaming, and SST config drives stage-specific behavior (protection, removal policy, provider region). The workflow includes local development, secrets commands, and GitHub Actions for automated deploys.

When to use it

  • Setting up a serverless Next.js app backed by DynamoDB
  • Managing stage-specific infrastructure behavior (dev/test/prod)
  • Deploying Next.js to AWS Lambda with streaming wrappers
  • Automating deploys with GitHub Actions and role-based AWS credentials
  • Managing secrets and local development with DynamoDB local

Best practices

  • Define stage-aware removal and protection to avoid accidental prod deletion
  • Keep environment values and secrets out of source; use SST secret commands or CI secrets
  • Link application stacks (site -> table) to propagate resources and environment variables
  • Use PAY_PER_REQUEST billing for low-maintenance DynamoDB operations unless capacity planning is required
  • Use OpenNext Lambda streaming wrapper for performance-sensitive Next.js streaming responses
  • Test locally with sst dev and DynamoDB Local before pushing CI deploys

Example use cases

  • Deploy a Next.js storefront that reads and writes product and session data to DynamoDB
  • Run feature-branch preview environments by deploying non-prod stages with automatic removal
  • Protect production by using retain removal policy and DNS for the prod domain
  • Store API auth tokens and application secrets via SST secrets and retrieve them in CI/CD
  • Use GitHub Actions to run npx sst deploy with an assumed AWS role for gated production releases

FAQ

How do I protect production resources from accidental removal?

Set removal to 'retain' and enable protect for the prod stage in the SST config so stacks cannot be removed without explicit changes.

Can I run the stack locally and connect to a local DynamoDB?

Yes. Use npx sst dev for local Lambda emulation and run a DynamoDB Local container. Set environment flags (e.g., DYNAMODB_LOCAL=true) to point the app to the local endpoint.