This guide covers everything you need to know about deploying SST applications to production and managing different environments.
Basic deployment
Deploy your application with a single command:
By default, this deploys to your personal stage (based on your username). For production, specify a stage:
sst deploy --stage production
What happens during deployment?
Build — SST builds your functions, containers, and sites
Create state — Pulumi creates a state file in your home provider
Deploy resources — Resources are created in order based on dependencies
Update config — Outputs are written to .sst/outputs.json
The first deployment to a new stage takes longer as SST sets up infrastructure.
Deployment stages
Stages let you deploy multiple isolated instances of your app:
# Personal development
sst deploy --stage dev
# Staging environment
sst deploy --stage staging
# Production
sst deploy --stage production
Each stage:
Has its own resources
Has its own AWS account (optionally)
Has separate secrets and config
Is completely isolated from other stages
Stage naming
SST automatically uses your username as the default stage. You can override this:
# Set via flag
sst deploy --stage my-stage
# Set via environment variable
SST_STAGE = my-stage sst deploy
# Set in .env
echo "SST_STAGE=my-stage" > .env
sst deploy
Use consistent stage names across your team: dev, staging, production.
Targeted deployments
Deploy specific components
Deploy only certain components:
sst deploy --target MyApi
This only deploys MyApi and its dependencies.
Exclude components
Skip specific components:
sst deploy --exclude MyFrontend
Useful when you want to deploy backend changes without rebuilding your frontend.
Multiple targets
Deploy multiple specific components:
sst deploy --target MyApi,MyDatabase
CI/CD deployment
Deploy from your CI/CD pipeline:
GitHub Actions
.github/workflows/deploy.yml
name : Deploy
on :
push :
branches : [ main ]
jobs :
deploy :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v4
- uses : actions/setup-node@v4
with :
node-version : 20
- name : Configure AWS credentials
uses : aws-actions/configure-aws-credentials@v4
with :
aws-access-key-id : ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region : us-east-1
- name : Install dependencies
run : npm install
- name : Deploy
run : npx sst deploy --stage production
GitLab CI
deploy :
stage : deploy
image : node:20
script :
- npm install
- npx sst deploy --stage production
only :
- main
variables :
AWS_ACCESS_KEY_ID : $AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY : $AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION : us-east-1
Environment variables
Set these in your CI/CD:
AWS_ACCESS_KEY_ID — AWS credentials
AWS_SECRET_ACCESS_KEY — AWS credentials
AWS_DEFAULT_REGION — AWS region
SST_STAGE — Deployment stage
SST_PRINT_LOGS=1 — Show detailed logs
Never commit AWS credentials to your repository. Use your CI/CD’s secret management.
Autodeploy with Console
The SST Console can automatically deploy your app on git push:
Setup autodeploy
Connect your GitHub repo to the SST Console
Configure deployment triggers in sst.config.ts:
export default $config ({
app ( input ) {
return {
name: "my-app" ,
home: "aws" ,
};
} ,
console: {
autodeploy: {
target ( event ) {
// Deploy main to production
if (
event . type === "branch" &&
event . branch === "main" &&
event . action === "pushed"
) {
return { stage: "production" };
}
// Deploy PRs to preview stages
if ( event . type === "pull_request" ) {
return { stage: `pr- ${ event . number } ` };
}
},
},
} ,
async run () {
// Your resources...
} ,
}) ;
Configure environments in the Console UI
Push to your repo
Deployment triggers
Branches:
if ( event . type === "branch" && event . branch === "main" ) {
return { stage: "production" };
}
Pull requests:
if ( event . type === "pull_request" ) {
return { stage: `pr- ${ event . number } ` };
}
Tags:
if ( event . type === "tag" && event . tag . startsWith ( "v" )) {
return { stage: "production" };
}
Skip deployment:
if ( event . type === "branch" && event . branch === "staging" ) {
return ; // Don't deploy
}
Runner configuration
Customize the build environment:
console : {
autodeploy : {
runner ( stage ) {
// Use larger instances for production
if ( stage === "production" ) {
return {
compute: "large" ,
timeout: "3 hours" ,
architecture: "arm64" ,
};
}
// Default for other stages
return {
compute: "medium" ,
timeout: "1 hour" ,
};
},
},
},
Custom workflow
Run custom commands during deployment:
console : {
autodeploy : {
async workflow ({ $ , event }) {
// Install dependencies
await $ `npm i -g pnpm` ;
await $ `pnpm i` ;
// Run tests
const { exitCode } = await $ `pnpm test` . nothrow ();
if ( exitCode !== 0 ) {
throw new Error ( "Tests failed" );
}
// Deploy or remove
if ( event . action === "removed" ) {
await $ `pnpm sst remove` ;
} else {
await $ `pnpm sst deploy` ;
}
},
},
},
Build concurrency
Control how many resources build concurrently:
SST_BUILD_CONCURRENCY_SITE = 2 sst deploy
Available controls:
Resource Default Variable Sites 1 SST_BUILD_CONCURRENCY_SITEFunctions 4 SST_BUILD_CONCURRENCY_FUNCTIONContainers 1 SST_BUILD_CONCURRENCY_CONTAINER
Increase concurrency on CI machines with more memory, decrease it on smaller machines.
Error handling
Continue on error
Deploy as many resources as possible even if some fail:
Useful when deploying a large app for the first time.
Retry failed deployments
If a deployment fails, fix the issue and run sst deploy again. SST will:
Skip successfully deployed resources
Retry failed resources
Continue from where it left off
Rollback
SST doesn’t have automatic rollbacks. To rollback:
Checkout the previous version of your code
Run sst deploy again
Or use git:
git revert HEAD
git push
sst deploy --stage production
Dev mode deployment
Deploy in dev mode without running sst dev:
This:
Deploys stub Lambda functions
Skips frontend deployments
Uses dev mode for databases (if configured)
Useful for testing dev mode in CI or on a remote server.
Removal
Remove all resources from a stage:
sst remove --stage staging
This deletes resources based on your removal setting:
app ( input ) {
return {
name: "my-app" ,
home: "aws" ,
removal: input . stage === "production" ? "retain" : "remove" ,
};
}
Options:
"remove" — Delete all resources
"retain" — Keep data resources (S3, DynamoDB), delete others
"retain-all" — Keep all resources
Be careful with sst remove in production. Set protect: true to prevent accidental removals.
Protect production
Prevent accidental removal:
app ( input ) {
return {
name: "my-app" ,
home: "aws" ,
protect: input . stage === "production" ,
};
}
Now sst remove --stage production will fail with an error.
Deployment outputs
After deployment, SST writes outputs to .sst/outputs.json:
{
"api" : "https://abc123.lambda-url.us-east-1.on.aws/" ,
"bucket" : "my-app-production-mybucket-a1b2c3d4"
}
Use these in scripts or external tools:
import outputs from "./.sst/outputs.json" ;
console . log ( "API URL:" , outputs . api );
Multi-region deployment
Deploy to multiple regions by running sst deploy with different AWS credentials:
# Deploy to us-east-1
AWS_REGION = us-east-1 sst deploy --stage production-us
# Deploy to eu-west-1
AWS_REGION = eu-west-1 sst deploy --stage production-eu
Or configure providers per stage:
app ( input ) {
return {
name: "my-app" ,
home: "aws" ,
providers: {
aws: {
region: input . stage . includes ( "eu" ) ? "eu-west-1" : "us-east-1" ,
},
},
};
}
Best practices
Use version control
Always deploy from version control:
git pull
sst deploy --stage production
Never deploy local changes that aren’t committed.
Test before production
Deploy to staging first:
# Test in staging
sst deploy --stage staging
# Verify it works
# Then deploy to production
sst deploy --stage production
Use separate AWS accounts
Use different AWS accounts for production and development:
Development: Your personal AWS account
Staging: Shared staging AWS account
Production: Production AWS account
Configure this in the SST Console environment settings.
Monitor deployments
Watch the deployment progress:
This shows detailed logs including build output and deployment steps.
Tag deployments
Use git tags for production deployments:
git tag v1.0.0
git push --tags
# Configure autodeploy to deploy tags
# Or deploy manually
sst deploy --stage production
Troubleshooting
Deployment hangs
If deployment hangs, check:
Network connectivity to AWS
AWS credentials are valid
No rate limiting from AWS
Cancel with Ctrl+C and retry.
Out of memory
Reduce build concurrency:
SST_BUILD_CONCURRENCY_SITE = 1 SST_BUILD_CONCURRENCY_FUNCTION = 2 sst deploy
State lock
If deployment fails and leaves a lock:
This removes the state lock so you can deploy again.
Resource limits
If you hit AWS resource limits, request an increase:
Lambda concurrent executions
CloudFormation stack limit
S3 bucket limit
Contact AWS Support to increase limits.
Next steps
Stage Management Manage multiple stages
Secrets Deploy with secrets
Console Monitor deployments
CI/CD Examples View CI/CD examples