deploying-to-aws
Specialized skill for deploying Next.js applications to AWS using SST (Serverless Stack) or Vercel, with DynamoDB integration, IAM configuration, and infrastructure as code. Use when setting up AWS resources or deploying production applications.
What this skill does
# Deploying to AWS
You are an expert in deploying production-ready Next.js applications to AWS with proper infrastructure, security, and best practices.
## Deployment Options
### Option 1: SST (Serverless Stack) - Recommended for AWS
- Full control over AWS resources
- Infrastructure as Code (IaC)
- Local development with AWS resources
- Type-safe infrastructure definitions
- Built specifically for Next.js + serverless
### Option 2: Vercel
- Simplest deployment
- Automatic CI/CD
- Global CDN
- Can still use AWS DynamoDB
- Great for getting started quickly
## SST Deployment (Recommended)
### Installation
```bash
npm install --save-dev sst aws-cdk-lib constructs
```
### Project Structure
```
my-app/
├── sst.config.ts # SST configuration
├── stacks/
│ ├── Database.ts # DynamoDB stack
│ ├── Web.ts # Next.js stack
│ └── Auth.ts # NextAuth config
├── app/ # Next.js app
└── lib/
└── db/
└── client.ts # DynamoDB client
```
### SST Configuration
```typescript
// sst.config.ts
import { SSTConfig } from 'sst';
import { Database } from './stacks/Database';
import { Web } from './stacks/Web';
export default {
config(_input) {
return {
name: 'my-app',
region: 'us-east-1',
};
},
stacks(app) {
app.stack(Database).stack(Web);
},
} satisfies SSTConfig;
```
### Database Stack
```typescript
// stacks/Database.ts
import { StackContext, Table } from 'sst/constructs';
export function Database({ stack }: StackContext) {
const table = new Table(stack, 'AppTable', {
fields: {
PK: 'string',
SK: 'string',
GSI1PK: 'string',
GSI1SK: 'string',
GSI2PK: 'string',
GSI2SK: 'string',
},
primaryIndex: {
partitionKey: 'PK',
sortKey: 'SK',
},
globalIndexes: {
GSI1: {
partitionKey: 'GSI1PK',
sortKey: 'GSI1SK',
},
GSI2: {
partitionKey: 'GSI2PK',
sortKey: 'GSI2SK',
},
},
stream: 'new-and-old-images', // Enable streams for real-time features
});
return { table };
}
```
### Web Stack
```typescript
// stacks/Web.ts
import { StackContext, NextjsSite, use } from 'sst/constructs';
import { Database } from './Database';
export function Web({ stack }: StackContext) {
const { table } = use(Database);
const site = new NextjsSite(stack, 'Site', {
path: '.',
environment: {
DYNAMODB_TABLE_NAME: table.tableName,
AWS_REGION: stack.region,
},
permissions: [table],
});
stack.addOutputs({
SiteUrl: site.url,
TableName: table.tableName,
});
return { site };
}
```
### Package.json Scripts
```json
{
"scripts": {
"dev": "sst dev next dev",
"build": "next build",
"start": "next start",
"deploy": "sst deploy --stage production",
"deploy:dev": "sst deploy --stage dev",
"remove": "sst remove --stage production",
"console": "sst console"
}
}
```
### Local Development with SST
```bash
# Start local development (creates real AWS resources in dev stage)
npm run dev
```
SST creates:
- Local Next.js dev server
- Real DynamoDB table in AWS (isolated dev stage)
- Local Lambda functions
- Live AWS resource binding
### Deployment
```bash
# Deploy to dev
npm run deploy:dev
# Deploy to production
npm run deploy
```
### Environment Variables
SST binds resources automatically, but for NextAuth and other secrets:
```typescript
// stacks/Web.ts
const site = new NextjsSite(stack, 'Site', {
path: '.',
environment: {
DYNAMODB_TABLE_NAME: table.tableName,
AWS_REGION: stack.region,
NEXTAUTH_URL: process.env.NEXTAUTH_URL!,
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET!,
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID!,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET!,
},
permissions: [table],
});
```
Set secrets in AWS:
```bash
npx sst secrets set NEXTAUTH_SECRET "your-secret-here" --stage production
npx sst secrets set GOOGLE_CLIENT_ID "your-client-id" --stage production
npx sst secrets set GOOGLE_CLIENT_SECRET "your-client-secret" --stage production
```
### DynamoDB Client Configuration
```typescript
// lib/db/client.ts
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
const client = new DynamoDBClient({
region: process.env.AWS_REGION || 'us-east-1',
});
export const docClient = DynamoDBDocumentClient.from(client, {
marshallOptions: {
convertEmptyValues: true,
removeUndefinedValues: true,
convertClassInstanceToMap: true,
},
unmarshallOptions: {
wrapNumbers: false,
},
});
export const TABLE_NAME = process.env.DYNAMODB_TABLE_NAME!;
```
### IAM Permissions
SST automatically configures IAM for:
- Lambda function execution role
- DynamoDB read/write access
- CloudWatch logs
- API Gateway invocation
Custom permissions:
```typescript
// stacks/Web.ts
const site = new NextjsSite(stack, 'Site', {
// ...
permissions: [
table,
'ses:SendEmail', // Additional permissions
's3:GetObject',
],
});
```
## Vercel Deployment
### Prerequisites
- Vercel account
- AWS account with DynamoDB table
- IAM user with DynamoDB access
### Setup
```bash
npm install -g vercel
vercel login
```
### Vercel Configuration
```json
// vercel.json
{
"build": {
"env": {
"DYNAMODB_TABLE_NAME": "@dynamodb-table-name",
"AWS_REGION": "@aws-region",
"AWS_ACCESS_KEY_ID": "@aws-access-key-id",
"AWS_SECRET_ACCESS_KEY": "@aws-secret-access-key"
}
},
"env": {
"DYNAMODB_TABLE_NAME": "@dynamodb-table-name",
"AWS_REGION": "@aws-region",
"AWS_ACCESS_KEY_ID": "@aws-access-key-id",
"AWS_SECRET_ACCESS_KEY": "@aws-secret-access-key",
"NEXTAUTH_URL": "@nextauth-url",
"NEXTAUTH_SECRET": "@nextauth-secret",
"GOOGLE_CLIENT_ID": "@google-client-id",
"GOOGLE_CLIENT_SECRET": "@google-client-secret"
}
}
```
### Set Environment Variables
```bash
vercel env add DYNAMODB_TABLE_NAME production
vercel env add AWS_REGION production
vercel env add AWS_ACCESS_KEY_ID production
vercel env add AWS_SECRET_ACCESS_KEY production
vercel env add NEXTAUTH_URL production
vercel env add NEXTAUTH_SECRET production
vercel env add GOOGLE_CLIENT_ID production
vercel env add GOOGLE_CLIENT_SECRET production
```
### Create DynamoDB Table (CloudFormation)
```yaml
# infrastructure/dynamodb-table.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: DynamoDB table for Next.js app
Resources:
AppTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: my-app-production
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: PK
AttributeType: S
- AttributeName: SK
AttributeType: S
- AttributeName: GSI1PK
AttributeType: S
- AttributeName: GSI1SK
AttributeType: S
- AttributeName: GSI2PK
AttributeType: S
- AttributeName: GSI2SK
AttributeType: S
KeySchema:
- AttributeName: PK
KeyType: HASH
- AttributeName: SK
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: GSI1
KeySchema:
- AttributeName: GSI1PK
KeyType: HASH
- AttributeName: GSI1SK
KeyType: RANGE
Projection:
ProjectionType: ALL
- IndexName: GSI2
KeySchema:
- AttributeName: GSI2PK
KeyType: HASH
- AttributeName: GSI2SK
KeyType: RANGE
Projection:
ProjectionType: ALL
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Tags:
- Key: Environment
Value: production
- Key: Application
Value: my-app
Outputs:
TableName:
Value: !Ref AppTable
Description: DynamoDB table namRelated in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.