CloudWatch Dashboard
A CDK construct that extends CloudWatch Dashboard directly with sensible defaults and built-in documentation, complete with:
- Automatic description widget at the top of the dashboard
- Support for initial widgets during construction
- Direct inheritance from CloudWatch Dashboard - no wrapper needed
- Flexible widget management with native addWidgets method
- Removal policy configuration for easy tear-down
- TypeScript-first design with comprehensive type safety
- cdk-nag compliance out of the box
- Jest unit tests with comprehensive CloudFormation validation
Features
- Dashboard Structure: CloudWatch dashboard with automatic layout:
- Description widget displayed prominently at the top (24 width, 2 height)
- Optional initial widgets positioned after description
- Direct access to all CloudWatch Dashboard methods and properties
- Documentation: Built-in dashboard documentation via description widget
- Flexibility: All CloudWatch dashboard properties are customizable
- Lifecycle Management: Automatic removal policy application for ephemeral environments
- Testing: Comprehensive Jest test suite with CloudFormation template validation
Usage
Basic Usage
import { CloudWatchDashboard } from '@leighton-digital/cloud-blocks';
// Minimal configuration
const dashboard = new CloudWatchDashboard(this, 'AppDashboard', {
dashboardName: 'application-monitoring',
dashboardDescription: 'Monitors API performance and error rates'
});
// CloudWatchDashboard IS a CloudWatch Dashboard - direct access to all methods
dashboard.addWidgets(/* your widgets */);
Advanced Configuration with Initial Widgets
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import { CloudWatchDashboard } from '@leighton-digital/cloud-blocks';
// Create metrics for monitoring
const apiRequestsMetric = new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: 'Count',
dimensionsMap: {
ApiName: 'MyAPI',
},
});
const errorRateMetric = new cloudwatch.Metric({
namespace: 'AWS/ApiGateway',
metricName: '4XXError',
dimensionsMap: {
ApiName: 'MyAPI',
},
});
const comprehensiveDashboard = new CloudWatchDashboard(this, 'ComprehensiveDashboard', {
dashboardName: 'production-monitoring',
dashboardDescription: `# Production API Monitoring
This dashboard provides comprehensive monitoring for our production API including:
- Request volume and latency trends
- Error rates and types
- Infrastructure health metrics
- Performance baselines and alerting thresholds`,
periodOverride: cloudwatch.PeriodOverride.AUTO,
initialWidgets: [
new cloudwatch.GraphWidget({
title: 'API Request Volume',
left: [apiRequestsMetric],
width: 12,
height: 6,
period: cdk.Duration.minutes(5),
}),
new cloudwatch.GraphWidget({
title: 'Error Rate',
left: [errorRateMetric],
width: 12,
height: 6,
period: cdk.Duration.minutes(5),
}),
],
});
Adding Widgets After Construction
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import { CloudWatchDashboard } from '@leighton-digital/cloud-blocks';
const dashboard = new CloudWatchDashboard(this, 'DynamicDashboard', {
dashboardName: 'dynamic-monitoring',
dashboardDescription: 'Dashboard that grows with our monitoring needs'
});
// Add widgets individually
dashboard.addWidgets(
new cloudwatch.SingleValueWidget({
title: 'Current TPS',
metrics: [tpsMetric],
width: 6,
height: 6,
})
);
// Add multiple widgets at once
dashboard.addWidgets(
new cloudwatch.GraphWidget({
title: 'Latency Trends',
left: [latencyP50, latencyP95, latencyP99],
width: 18,
height: 6,
}),
new cloudwatch.AlarmWidget({
title: 'Active Alarms',
alarms: [criticalAlarm, warningAlarm],
width: 6,
height: 6,
})
);
Integration with Monitoring Constructs
import * as cdk from 'aws-cdk-lib';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as cloudwatch from 'aws-cdk-lib/aws-cloudwatch';
import { CloudWatchDashboard } from '@leighton-digital/cloud-blocks';
export class MonitoringStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Create API Gateway
const api = new apigateway.RestApi(this, 'MyApi', {
restApiName: 'production-api',
});
// Create monitoring dashboard
const dashboard = new CloudWatchDashboard(this, 'ApiMonitoring', {
dashboardName: `${this.stackName}-api-monitoring`,
dashboardDescription: `Monitoring dashboard for ${api.restApiName}
## Key Metrics
- **Request Volume**: Total requests per minute
- **Error Rates**: 4XX and 5XX error percentages
- **Latency**: Response time percentiles
- **Throttling**: Request throttling incidents
## Operational Notes
- Alerts are configured for error rates > 5%
- Expected latency P95 < 2000ms
- Contact: platform-team@company.com`,
initialWidgets: [
new cloudwatch.GraphWidget({
title: 'API Request Volume',
left: [api.metricCount()],
width: 12,
height: 6,
}),
new cloudwatch.GraphWidget({
title: 'API Latency',
left: [api.metricLatency()],
width: 12,
height: 6,
}),
],
});
// Add additional monitoring widgets based on your needs
dashboard.addWidgets(
new cloudwatch.GraphWidget({
title: 'Error Rates',
left: [api.metricClientError(), api.metricServerError()],
width: 24,
height: 6,
})
);
}
}
Configuring Removal Policy
import * as cdk from 'aws-cdk-lib';
import { CloudWatchDashboard } from '@leighton-digital/cloud-blocks';
// Default behavior: Dashboard is deleted when stack is deleted
const ephemeralDashboard = new CloudWatchDashboard(this, 'EphemeralDashboard', {
dashboardName: 'ephemeral-monitoring',
dashboardDescription: 'Dashboard for development environment',
// removalPolicy defaults to RemovalPolicy.DESTROY
});
// Production dashboard: Retain the dashboard when stack is deleted
const productionDashboard = new CloudWatchDashboard(this, 'ProductionDashboard', {
dashboardName: 'production-monitoring',
dashboardDescription: 'Critical production metrics - preserved across deployments',
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
// Snapshot before deletion (if supported by the resource)
const snapshotDashboard = new CloudWatchDashboard(this, 'SnapshotDashboard', {
dashboardName: 'snapshot-monitoring',
dashboardDescription: 'Dashboard that will be snapshotted before deletion',
removalPolicy: cdk.RemovalPolicy.SNAPSHOT,
});
Props
All props are inherited from the CloudWatch Dashboard construct, except for the following:
widgets
: Automatically managed by the construct (useinitialWidgets
andaddWidgets()
instead)
The following additional props are available:
dashboardDescription
: Required - Descriptive text displayed at the top of the dashboardinitialWidgets
: Optional - Array of widgets to add during construction (after description widget)removalPolicy
: Optional - Policy to apply when the dashboard is removed from the stack (defaults toRemovalPolicy.DESTROY
)
What gets created
- CloudWatch Dashboard:
${constructId}
(the construct itself)- Description text widget (width: 24, height: 2)
- Any initial widgets specified in props
- Configured with specified dashboard properties
- Configurable removal policy (defaults to DESTROY for easy cleanup)
Dashboard Layout Best Practices
The construct follows CloudWatch dashboard best practices:
- Description Widget: Always appears first, full width (24), providing context
- Widget Sizing: Use consistent widget dimensions (multiples of 6 for width)
- Logical Grouping: Group related metrics together
- Information Hierarchy: Most important metrics should appear near the top
Recommended Widget Layouts
// Full-width sections for major metric groups
new cloudwatch.GraphWidget({
title: 'Primary KPIs',
width: 24, // Full width
height: 6,
// ... metrics
});
// Side-by-side comparison widgets
new cloudwatch.GraphWidget({
title: 'Requests',
width: 12, // Half width
height: 6,
// ... metrics
});
new cloudwatch.GraphWidget({
title: 'Errors',
width: 12, // Half width
height: 6,
// ... metrics
});
// Number widgets for key indicators
new cloudwatch.SingleValueWidget({
title: 'Current TPS',
width: 6, // Quarter width
height: 6,
// ... metrics
});
Markdown Support in Descriptions
The dashboard description supports full Markdown formatting:
const dashboard = new CloudWatchDashboard(this, 'RichDashboard', {
dashboardName: 'comprehensive-monitoring',
dashboardDescription: `# Production System Health
## 🎯 Key Performance Indicators
- **Availability**: > 99.9% uptime
- **Latency**: P95 < 500ms
- **Error Rate**: < 0.1%
## 📊 Dashboard Sections
1. **Traffic Patterns** - Request volume and geographic distribution
2. **Performance Metrics** - Latency percentiles and throughput
3. **Error Analysis** - Error rates, types, and root cause indicators
4. **Infrastructure Health** - CPU, memory, and resource utilization
## 🚨 Alert Thresholds
| Metric | Warning | Critical |
|--------|---------|----------|
| Error Rate | 1% | 5% |
| Latency P95 | 1000ms | 2000ms |
| CPU Usage | 70% | 85% |
> 📞 **On-Call**: platform-team@company.com
> 📚 **Runbooks**: https://wiki.company.com/runbooks`,
});
Operational notes & caveats
- Widget Limits: CloudWatch dashboards support up to 500 widgets per dashboard
- Refresh Rates: Dashboards auto-refresh every minute; use periodOverride for custom behavior
- Cross-Account Metrics: Requires appropriate IAM permissions for cross-account metric access
- Regional Considerations: Dashboards exist in specific regions; metrics from other regions incur additional charges
- Performance: Large dashboards with many metrics may have slower load times
- Removal Policy: Use
RemovalPolicy.RETAIN
for production dashboards to preserve them across stack updates. DefaultDESTROY
policy is ideal for development environments.
Extending
- Custom Widgets: Create custom widgets using CloudWatch Insights or third-party integrations
- Programmatic Updates: Use the dashboard construct in CI/CD pipelines for dynamic dashboard generation
- Alerting Integration: Combine with CloudWatch Alarms for comprehensive monitoring solutions
- Cross-Account Dashboards: Configure cross-account IAM roles for centralized monitoring
Troubleshooting
- "Widgets not appearing" → Verify metric permissions and regional configuration
- "Dashboard not updating" → Check metric timestamps and CloudWatch service health
- "Cross-region metrics failing" → Ensure IAM permissions for cross-region access
- "Performance issues" → Reduce widget count or optimize metric queries for faster loading
- "Access denied errors" → Verify CloudWatch dashboard permissions in IAM policies