Learn how to deploy Pika to AWS using AWS CDK (Cloud Development Kit), providing type-safe infrastructure as code for your application.
What You'll Accomplish
Section titled “What You'll Accomplish”By the end of this guide, you will:
- Configure AWS credentials
- Set up your CDK project
- Deploy the Pika service stack
- Deploy the Pika chat application
- Configure environment variables
- Verify your deployment
Prerequisites
Section titled “Prerequisites”- AWS account with appropriate permissions
- AWS CLI installed and configured
- Node.js 22+ installed
- pnpm package manager
- Pika project cloned locally
Understanding CDK Deployment
Section titled “Understanding CDK Deployment”AWS CDK uses TypeScript to define cloud infrastructure, which is then synthesized into CloudFormation templates.
Pika Stacks
Section titled “Pika Stacks”Pika typically consists of two stacks:
Pika Service Stack (
services/pika/) - Backend infrastructure- Lambda functions
- DynamoDB tables
- API Gateway
- IAM roles and policies
Pika Chat Stack (
apps/pika-chat/infra/) - Frontend application- CloudFront distribution
- S3 bucket for static assets
- Lambda@Edge for SSR
Step 1: Configure AWS Credentials
Section titled “Step 1: Configure AWS Credentials”Set up your AWS credentials for deployment.
Using AWS CLI
Section titled “Using AWS CLI”aws configure
# You'll be prompted for:# AWS Access Key ID: YOUR_ACCESS_KEY# AWS Secret Access Key: YOUR_SECRET_KEY# Default region name: us-east-1# Default output format: jsonUsing Named Profiles
Section titled “Using Named Profiles”# Configure a named profileaws configure --profile pika-dev
# Set the profile for deploymentexport AWS_PROFILE=pika-devVerify Configuration
Section titled “Verify Configuration”aws sts get-caller-identityYou should see your AWS account information.
Step 2: Install Dependencies
Section titled “Step 2: Install Dependencies”Install CDK and project dependencies.
Install AWS CDK CLI
Section titled “Install AWS CDK CLI”npm install -g aws-cdk
# Verify installationcdk --versionInstall Project Dependencies
Section titled “Install Project Dependencies”# From project rootpnpm installStep 3: Configure Environment
Section titled “Step 3: Configure Environment”Set up environment variables and configuration.
Create Environment File
Section titled “Create Environment File”Location: services/pika/.env
# Deployment stageSTAGE=dev
# AWS configurationAWS_REGION=us-east-1AWS_ACCOUNT_ID=123456789012
# OpenAI API key (if using OpenAI models)OPENAI_API_KEY=your-openai-api-key
# Other configurationPIKA_SERVICE_NAME=pikaUpdate CDK Context
Section titled “Update CDK Context”Location: services/pika/cdk.json
{ "app": "npx ts-node --project tsconfig.json bin/pika.ts", "context": { "@aws-cdk/core:enableStackNameDuplicates": "true", "aws-cdk:enableDiffNoFail": "true", "@aws-cdk/core:stackRelativeExports": "true", "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, "@aws-cdk/aws-kms:defaultKeyPolicies": true }}Step 4: Configure Stack Tags (Optional)
Section titled “Step 4: Configure Stack Tags (Optional)”Add AWS tags to all resources in your CDK stacks for better organization and cost tracking.
Add Tags in pika-config.ts
Section titled “Add Tags in pika-config.ts”Location: pika-config.ts
export const pikaConfig: PikaConfig = { // ... existing config stackTags: { // Common tags applied to BOTH Pika service and Pika Chat stacks common: { 'ManagedBy': 'Pika', 'Project': 'MyCompany', 'env': '{stage}', // Replaced with deployment stage 'CostCenter': '12345' },
// Tags specific to the Pika service stack (backend) pikaServiceTags: { 'app': '{pika.projNameKebabCase}', // Pika service name 'Tier': 'Backend' },
// Tags specific to the Pika Chat stack (frontend) pikaChatTags: { 'app': '{pikaChat.projNameKebabCase}', // Pika Chat app name 'Tier': 'Frontend' },
// Component tag names for cost tracking (optional but recommended) componentTagNames: ['component'] }};Tag Structure
Section titled “Tag Structure”The stackTags configuration has four sections:
common: Tags applied to both Pika service and Pika Chat stackspikaServiceTags: Additional tags only for the backend service stack (merged withcommon, overwrites on conflict)pikaChatTags: Additional tags only for the frontend chat stack (merged withcommon, overwrites on conflict)componentTagNames: Array of tag names to use for component identification (for cost tracking and analysis)
Supported Placeholders
Section titled “Supported Placeholders”Tags are interpolated at CDK synth time:
Basic Placeholders:
{stage}- Deployment stage (e.g., 'dev', 'prod'){timestamp}- Current timestamp in ISO 8601 format{accountId}- AWS account ID where stack is deployed{region}- AWS region where stack is deployed
Pika Project Name Placeholders:
{pika.projNameL}- Pika project name (lowercase){pika.projNameKebabCase}- Pika project name (kebab-case){pika.projNameTitleCase}- Pika project name (TitleCase){pika.projNameCamel}- Pika project name (camelCase){pika.projNameHuman}- Pika project name (human-readable)
Pika Chat Project Name Placeholders:
{pikaChat.projNameL}- Pika Chat project name (lowercase){pikaChat.projNameKebabCase}- Pika Chat project name (kebab-case){pikaChat.projNameTitleCase}- Pika Chat project name (TitleCase){pikaChat.projNameCamel}- Pika Chat project name (camelCase){pikaChat.projNameHuman}- Pika Chat project name (human-readable)
Advanced: Custom Tag Modifications
Section titled “Advanced: Custom Tag Modifications”For the Pika service stack only, you can override the modifyStackTags method in custom-stack-defs.ts:
Location: services/pika/lib/stacks/custom-stack-defs.ts
modifyStackTags(tags: Record<string, string>, stage: string): Record<string, string> { return { ...tags, 'CustomTag': 'CustomValue', 'Stage': stage.toUpperCase(), 'Owner': 'DevOps Team' };}Tag Validation
Section titled “Tag Validation”The system automatically validates tags and warns about:
- Keys exceeding 128 characters
- Values exceeding 256 characters
- Invalid characters (only letters, numbers, spaces,
_ . : / = + - @allowed) - Reserved
aws:prefix
Component Tags for Cost Tracking
Section titled “Component Tags for Cost Tracking”Component tags help you understand cost breakdowns within each AWS service. While AWS Cost Explorer lets you filter by service (e.g., "show me all Lambda costs"), component tags let you see which specific Lambda functions or resources are driving those costs.
Why Component Tags Matter:
When you look at AWS Cost Explorer, you can filter by service (S3, Lambda, DynamoDB, etc.), but you can't easily see:
- Which Lambda function is consuming the most cost
- Which DynamoDB table has the highest throughput charges
- Which inference profile is being used most heavily for Bedrock costs
Component tags solve this by tagging every infrastructure resource with a descriptive component name.
Configure Component Tag Names:
Add a componentTagNames array to your stack tags configuration:
export const pikaConfig: PikaConfig = { // ... existing config stackTags: { common: { 'ManagedBy': 'Pika', 'env': '{stage}' }, // Tag names to use for component identification componentTagNames: ['component'] }};How It Works:
With componentTagNames: ['component'], every infrastructure resource gets tagged with a component identifier:
// Examples of how resources are tagged:component: ConverseLambda // The main conversation handler Lambdacomponent: ChatMessagesTable // DynamoDB table for messagescomponent: PikaFilesBucket // S3 bucket for file storagecomponent: OpenSearchDomain // OpenSearch domain for session insightscomponent: Claude4SonnetInferenceProfile // Bedrock inference profilecomponent: ECSCluster // ECS cluster for chat webappcomponent: FargateService // Fargate service running the webappCost Explorer Analysis:
Once deployed, you can use AWS Cost Explorer to:
- Filter by service: e.g., "AWS Lambda"
- Group by tag: Select your component tag name (e.g.,
component) - See breakdown: View costs for each Lambda function separately:
- ConverseLambda: $X
- ChatbotApiLambda: $Y
- KeyRotationLambda: $Z
This is particularly valuable for:
- Bedrock costs: See which inference profiles (models) are most expensive
- Lambda costs: Identify which functions need optimization
- DynamoDB costs: Find which tables have high read/write costs
- S3 costs: Determine which buckets consume the most storage
Using Multiple Tag Names:
You can specify multiple component tag names to support different organizational structures:
componentTagNames: ['component', 'resource-type', 'cost-center']This creates three tags on each resource:
// All three tags get the same component valuecomponent: ConverseLambdaresource-type: ConverseLambdacost-center: ConverseLambdaTagging Custom Infrastructure:
If you add custom infrastructure in custom-stack-defs.ts, use the applyComponentTags helper to ensure consistent tagging:
// In services/pika/lib/stacks/custom-stack-defs.tsaddStackResoucesAfterWeCreateThePikaConstruct(): void { const myCustomLambda = new lambda.Function(this.stack, 'MyCustomFunction', { // ... lambda configuration });
// Apply component tags automatically this.applyComponentTags(myCustomLambda, 'MyCustomLambda');}// In apps/pika-chat/infra/lib/stacks/custom-stack-defs.tsaddStackResoucesAfterWeCreateThePikaChatConstruct(): void { const myBucket = new s3.Bucket(this.stack, 'MyCustomBucket', { // ... bucket configuration });
// Apply component tags automatically this.applyComponentTags(myBucket, 'MyCustomS3Bucket');}Tag Size Limits
Section titled “Tag Size Limits”AWS Lambda has a 4KB total limit for all environment variables. To ensure your tags don't consume too much space, Pika enforces a 500 byte limit for tag environment variables (STACK_TAGS + COMPONENT_TAG_NAMES combined).
Why 500 bytes?
This conservative limit leaves 3.5KB for all other environment variables your application needs (API endpoints, configuration values, secrets, etc.).
Check Your Tag Size:
You can verify your tag configuration size before deployment:
// In pika-config.ts or a Node.js REPLconst stackTags = { common: { /* your tags */ }, pikaServiceTags: { /* your tags */ }, pikaChatTags: { /* your tags */ }, componentTagNames: ['component']};
// Calculate size for Pika service stackconst serviceStackTags = { ...stackTags.common, ...stackTags.pikaServiceTags };const serviceSize = JSON.stringify(serviceStackTags).length + JSON.stringify(stackTags.componentTagNames || []).length;console.log('Pika service stack tag size:', serviceSize, 'bytes');
// Calculate size for Pika Chat stackconst chatStackTags = { ...stackTags.common, ...stackTags.pikaChatTags };const chatSize = JSON.stringify(chatStackTags).length + JSON.stringify(stackTags.componentTagNames || []).length;console.log('Pika Chat stack tag size:', chatSize, 'bytes');
// Both should be under 500 bytesif (serviceSize > 500 || chatSize > 500) { console.error('Tags exceed 500 byte limit!');} else { console.log('Tags are within size limits');}What Happens if You Exceed the Limit?
If your tags exceed 500 bytes, CDK synthesis will fail with a clear error message before any resources are deployed:
Error: Tag environment variables exceed size limit.Total size: 623 bytes, maximum: 500 bytes.STACK_TAGS size: 589 bytes, COMPONENT_TAG_NAMES size: 34 bytes.Please reduce the number or length of tags in your pika-config.ts stackTags configuration.Tips to Reduce Tag Size:
- Use shorter tag keys:
envinstead ofEnvironment - Use shorter tag values:
devinstead ofdevelopment - Remove unnecessary tags
- Reduce the number of
componentTagNamesentries - Use placeholder interpolation for repeated values
- Tags are optional - if not configured, no tags are applied
- Tags apply to all resources in each stack automatically
- Use
commonfor shared tags, andpikaServiceTags/pikaChatTagsfor stack-specific tags - Stack-specific tags overwrite common tags if there's a naming conflict
- Component tags help you analyze costs by specific infrastructure component within each AWS service
- Tag environment variables are limited to 500 bytes to leave room for other configuration
Step 5: Bootstrap CDK
Section titled “Step 5: Bootstrap CDK”Bootstrap your AWS environment for CDK deployments (one-time setup per account/region).
cd services/pika
# Bootstrap with your account and regioncdk bootstrap aws://123456789012/us-east-1This creates necessary resources for CDK deployments (S3 bucket, IAM roles, etc.).
Step 6: Deploy Pika Service Stack
Section titled “Step 6: Deploy Pika Service Stack”Deploy the backend infrastructure.
Preview Changes
Section titled “Preview Changes”cd services/pika
# See what will be createdpnpm cdk:diffDeploy Stack
Section titled “Deploy Stack”# Deploy with approval promptspnpm cdk:deploy
# Or deploy without prompts (use with caution)pnpm cdk:deploy --require-approval neverDeployment Output
Section titled “Deployment Output”You'll see progress as resources are created:
✨ Synthesis time: 5.32s
pika-dev: deploying...pika-dev: creating CloudFormation changeset...
✅ pika-dev
✨ Deployment time: 425.67s
Outputs:pika-dev.ConverseFunctionUrl = https://abc123.lambda-url.us-east-1.on.aws/pika-dev.ApiGatewayUrl = https://xyz789.execute-api.us-east-1.amazonaws.com/dev/
Stack ARN:arn:aws:cloudformation:us-east-1:123456789012:stack/pika-dev/guidSave Important Outputs
Section titled “Save Important Outputs”Save the function URLs and API endpoints - you'll need them for configuration.
Step 7: Deploy Pika Chat Stack
Section titled “Step 7: Deploy Pika Chat Stack”Deploy the frontend application.
Configure Chat App Environment
Section titled “Configure Chat App Environment”Location: apps/pika-chat/.env
# StagePUBLIC_STAGE=dev
# Backend API endpoint (from service stack output)PUBLIC_API_URL=https://xyz789.execute-api.us-east-1.amazonaws.com/dev
# Converse function URL (from service stack output)PUBLIC_CONVERSE_URL=https://abc123.lambda-url.us-east-1.on.aws/
# AWS regionPUBLIC_AWS_REGION=us-east-1Deploy Chat Stack
Section titled “Deploy Chat Stack”cd apps/pika-chat
# Preview changespnpm cdk:diff
# Deploypnpm cdk:deployDeployment Output
Section titled “Deployment Output”✅ pika-chat-dev
Outputs:pika-chat-dev.CloudFrontUrl = https://d123456.cloudfront.netpika-chat-dev.S3BucketName = pika-chat-dev-bucket-abc123
Stack ARN:arn:aws:cloudformation:us-east-1:123456789012:stack/pika-chat-dev/guidAccess Your Application
Section titled “Access Your Application”Open the CloudFront URL in your browser to access your deployed Pika chat application.
Step 8: Configure Custom Domain (Optional)
Section titled “Step 8: Configure Custom Domain (Optional)”Set up a custom domain for your application.
Prerequisites
Section titled “Prerequisites”- Domain registered (Route 53, Google Domains, etc.)
- SSL certificate in ACM (must be in us-east-1 for CloudFront)
Update Chat Stack
Section titled “Update Chat Stack”Location: apps/pika-chat/infra/lib/pika-chat-stack.ts
const distribution = new cloudfront.Distribution(this, 'Distribution', { // ... other config domainNames: ['chat.yourdomain.com'], certificate: acm.Certificate.fromCertificateArn( this, 'Certificate', 'arn:aws:acm:us-east-1:123456789012:certificate/your-cert-id' )});Create Route 53 Record
Section titled “Create Route 53 Record”import * as route53 from 'aws-cdk-lib/aws-route53';import * as targets from 'aws-cdk-lib/aws-route53-targets';
const zone = route53.HostedZone.fromLookup(this, 'Zone', { domainName: 'yourdomain.com'});
new route53.ARecord(this, 'ChatARecord', { zone: zone, recordName: 'chat', target: route53.RecordTarget.fromAlias( new targets.CloudFrontTarget(distribution) )});Redeploy
Section titled “Redeploy”pnpm cdk:deployStep 9: Verify Deployment
Section titled “Step 9: Verify Deployment”Test your deployed application.
Check Service Health
Section titled “Check Service Health”# Test converse functioncurl https://abc123.lambda-url.us-east-1.on.aws/health
# Test API Gatewaycurl https://xyz789.execute-api.us-east-1.amazonaws.com/dev/healthTest Chat Application
Section titled “Test Chat Application”- Open CloudFront URL in browser
- Verify authentication works
- Test sending a message
- Check agent responds correctly
Check CloudWatch Logs
Section titled “Check CloudWatch Logs”# View Lambda logsaws logs tail /aws/lambda/pika-dev-converse --follow
# View API Gateway logsaws logs tail /aws/apigateway/pika-dev --followVerify Bedrock Inference Profiles
Section titled “Verify Bedrock Inference Profiles”If you're using Bedrock models, you can verify your inference profiles were created:
# List all application inference profilesaws bedrock list-inference-profiles --type-equals APPLICATION
# Filter for your stack's profilesaws bedrock list-inference-profiles --type-equals APPLICATION \ --query 'inferenceProfileSummaries[?contains(inferenceProfileName, `pika-dev`)]'Common Tasks
Section titled “Common Tasks”Update Deployment
Section titled “Update Deployment”# Service stackcd services/pikapnpm cdk:deploy
# Chat stackcd apps/pika-chatpnpm cdk:deployRollback Deployment
Section titled “Rollback Deployment”# List stack historyaws cloudformation describe-stack-events --stack-name pika-dev
# Rollback to previous version# In CloudFormation console: Stack Actions → Roll backDelete Stacks
Section titled “Delete Stacks”# Delete chat stack firstcd apps/pika-chatpnpm cdk:destroy
# Then delete service stackcd services/pikapnpm cdk:destroyTesting Checklist
Section titled “Testing Checklist”Best Practices
Section titled “Best Practices”Security
Section titled “Security”- Use IAM Roles: Don't hardcode credentials
- Principle of Least Privilege: Grant minimal necessary permissions
- Secrets Management: Store secrets in Secrets Manager
- Enable CloudTrail: Audit AWS API calls
Cost Optimization
Section titled “Cost Optimization”- Use On-Demand Pricing: Start with on-demand, optimize later
- Monitor Costs: Set up billing alerts
- Right-Size Resources: Adjust Lambda memory and timeout
- Cleanup Unused Resources: Remove old stacks and resources
Deployment
Section titled “Deployment”- Use Stages: Separate dev, staging, and production
- Preview Changes: Always run
cdk:diffbefore deploy - Automated Testing: Test before production deployment
- Gradual Rollout: Consider blue/green deployments
Troubleshooting
Section titled “Troubleshooting”CDK Bootstrap Fails
Section titled “CDK Bootstrap Fails”# Check permissionsaws iam get-user
# Ensure you have CloudFormation permissionsaws cloudformation describe-stacksDeployment Timeout
Section titled “Deployment Timeout”- Check CloudFormation events in AWS Console
- Increase Lambda timeout if needed
- Review security group and VPC settings
Application Not Loading
Section titled “Application Not Loading”- Check CloudFront distribution status (wait for deployment)
- Verify S3 bucket permissions
- Check browser console for errors
- Verify API URLs in environment variables
Permission Errors
Section titled “Permission Errors”- Review IAM role policies in CloudFormation
- Check Lambda execution role
- Verify API Gateway permissions
Next Steps
Section titled “Next Steps”- Deploy Using Serverless Framework - Alternative deployment
- Set Up Local Development - Local testing
- Use Stack Management - Manage deployments
Related Documentation
Section titled “Related Documentation”- AWS CDK Documentation - Official AWS docs
- CloudFormation Best Practices - AWS guidance
- Pika Architecture - System architecture