S3StateStore
The S3StateStore provides reliable, scalable state storage for Alchemy applications using Amazon S3. It's designed for cloud-based deployments where you need durable, shared state storage across multiple environments or team members.
Basic Usage
Configure Alchemy to use S3 for state storage:
import { S3StateStore } from "alchemy/aws";
const app = await alchemy("my-app", {
stage: "prod",
phase: process.argv.includes("--destroy") ? "destroy" : "up",
stateStore: (scope) => new S3StateStore(scope, {
bucketName: "my-app-alchemy-state",
region: "us-east-1"
})
});
Configuration Options
Bucket Name and Region
Specify the S3 bucket and AWS region for state storage:
import { S3StateStore } from "alchemy/aws";
const app = await alchemy("my-app", {
stateStore: (scope) => new S3StateStore(scope, {
bucketName: "my-company-alchemy-state",
region: "us-west-2"
})
});
Custom Prefix
Use a prefix to organize state files when sharing buckets across projects:
import { S3StateStore } from "alchemy/aws";
const app = await alchemy("my-app", {
stateStore: (scope) => new S3StateStore(scope, {
bucketName: "shared-alchemy-state",
prefix: "my-team/my-app/",
region: "us-east-1"
})
});
Prerequisites
Create S3 Bucket
The S3 bucket must exist before using S3StateStore. Use the Alchemy bootstrap command (recommended) or create it manually:
# Recommended: Use Alchemy bootstrap
alchemy bootstrap s3
# Or create manually with AWS CLI
aws s3 mb s3://my-app-alchemy-state --region us-east-1
Configure AWS Credentials
Ensure AWS credentials are configured via:
- AWS credentials file (
~/.aws/credentials
) - Environment variables (
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
) - IAM roles (for EC2/Lambda)
- AWS CLI profile
The credentials need S3 permissions for the target bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-alchemy-state",
"arn:aws:s3:::my-app-alchemy-state/*"
]
}
]
}
State Organization
S3StateStore organizes state files using scope-based prefixes:
my-app-alchemy-state/
alchemy/my-app/dev/
my-resource
my-other-resource
alchemy/my-app/prod/
my-resource
my-other-resource
Keys containing forward slashes are converted to colons for S3 compatibility:
- Resource key:
api/database/connection
- S3 object key:
alchemy/my-app/dev/api:database:connection
Environment-Specific Configuration
Development
Use a development-specific bucket or prefix:
const isDev = process.env.NODE_ENV === "development";
const app = await alchemy("my-app", {
stage: isDev ? "dev" : "prod",
stateStore: (scope) => new S3StateStore(scope, {
bucketName: isDev ? "my-app-dev-state" : "my-app-prod-state",
region: "us-east-1"
})
});
Team Environments
Share state across team members with appropriate bucket permissions:
const app = await alchemy("my-app", {
stage: "shared",
stateStore: (scope) => new S3StateStore(scope, {
bucketName: "team-shared-alchemy-state",
prefix: `${process.env.USER || "unknown"}/`,
region: "us-east-1"
})
});
Error Handling
S3StateStore includes built-in retry logic and proper error handling:
- NoSuchBucket: Clear error message if bucket doesn't exist
- NoSuchKey: Gracefully handles missing state files
- Network errors: Automatic retry with exponential backoff
- Permissions: Clear AWS permission error messages
Performance Considerations
- Eventual consistency: S3 provides eventual consistency for state operations
- Batch operations: Uses concurrent requests for multi-key operations
- Network latency: Consider bucket region proximity to your deployment location
- Costs: S3 charges for requests and storage (typically very low for state files)