aws-ecs: Add L2 construct for `CfnExpressGatewayService`
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### Describe the feature
AWS recently announced [ECS Express Mode](https://aws.amazon.com/about-aws/whats-new/2025/11/announcing-amazon-ecs-express-mode/), which simplifies deploying containerized applications on ECS.
While CDK v2.230.0 includes the L1 construct `CfnExpressGatewayService`, there is currently **no L2 construct** for this resource type. This forces developers to work with the low-level CloudFormation construct, missing out on the benefits of CDK's higher-level abstractions.
### Use Case
Developers using ECS Express Mode need a type-safe, intuitive CDK construct that:
1. **Simplifies configuration** - Provides sensible defaults and validation
2. **Improves discoverability** - Easy to find through IDE autocomplete alongside `Ec2Service` and `FargateService`
3. **Enables integration** - Works seamlessly with other CDK ECS constructs
4. **Reduces boilerplate** - Abstracts common patterns and configurations
Currently, using `CfnExpressGatewayService` requires:
- Manual ARN mapping for clusters and roles
- Explicit configuration of all properties with no defaults
- No type safety for nested objects like `primaryContainer` and `networkConfiguration`
- No helper methods for common operations
### Proposed Solution
Introduce an **`ExpressGatewayService`** L2 construct that follows the established pattern of `Ec2Service` and `FargateService`.
#### Proposed API
```typescript
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
declare const cluster: ecs.Cluster;
declare const vpc: ec2.Vpc;
const expressService = new ecs.ExpressGatewayService(this, 'MyExpressService', {
cluster,
serviceName: 'my-express-service',
// Container configuration
taskDefinition: new ecs.ExpressGatewayTaskDefinition(this, 'TaskDef', {
cpu: 1024,
memoryMiB: 2048,
containers: [
{
image: ecs.ContainerImage.fromRegistry('public.ecr.aws/docker/library/nginx:latest'),
containerPort: 80,
environment: {
NODE_ENV: 'production',
},
},
],
}),
// Or simplified inline container definition
containerImage: ecs.ContainerImage.fromRegistry('public.ecr.aws/docker/library/httpd:2.4'),
containerPort: 80,
cpu: 1024,
memoryMiB: 2048,
// Health check
healthCheckPath: '/',
// Auto-scaling (optional)
minCapacity: 2,
maxCapacity: 10,
targetCpuUtilization: 70,
// Network configuration (with sensible defaults)
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },
securityGroups: [securityGroup],
// Infrastructure role (auto-created if not provided)
infrastructureRole: customInfrastructureRole,
});
// Access generated resources
expressService.loadBalancer; // IApplicationLoadBalancer
expressService.targetGroup; // IApplicationTargetGroup
expressService.service; // IBaseService
```
#### Key Features
**1. Smart Defaults:**
- Auto-create execution and infrastructure roles with appropriate policies
- Default to private subnets with egress
- Sensible health check configurations
- Default auto-scaling policies
**2. Flexible Container Configuration:**
- Support both inline container definition and TaskDefinition
- Type-safe container properties
- Helper methods for common configurations
**3. Integration with CDK Constructs:**
- Works with existing `Cluster` constructs
- Returns typed references to ALB, target groups, and services
- Implements `IConnectable` for security group rules
- Supports CDK grants and permissions
**4. Developer Experience:**
- Follows naming conventions of `Ec2Service` and `FargateService`
- Clear error messages and validation
- Comprehensive documentation and examples
- TypeScript autocomplete support
### Alternative: Enhanced ExpressGatewayTaskDefinition
Additionally, consider introducing an **`ExpressGatewayTaskDefinition`** L2 construct:
```typescript
const taskDefinition = new ecs.ExpressGatewayTaskDefinition(this, 'TaskDef', {
cpu: 1024,
memoryMiB: 2048,
// Primary container (required)
primaryContainer: {
image: ecs.ContainerImage.fromRegistry('nginx'),
containerPort: 80,
environment: { NODE_ENV: 'production' },
secrets: { API_KEY: ecs.Secret.fromSecretsManager(secret) },
},
// Optional sidecar containers
containers: [
{
name: 'log-router',
image: ecs.ContainerImage.fromRegistry('fluent-bit'),
essential: false,
},
],
});
const service = new ecs.ExpressGatewayService(this, 'Service', {
cluster,
taskDefinition,
healthCheckPath: '/health',
});
```
### Current Workaround
Developers must currently use the L1 construct directly:
```typescript
import { CfnExpressGatewayService } from 'aws-cdk-lib/aws-ecs';
const expressService = new CfnExpressGatewayService(this, 'ExpressGateway', {
serviceName: 'my-service',
cluster: cluster.clusterArn, // Must manually get ARN
infrastructureRoleArn: infrastructureRole.roleArn,
executionRoleArn: executionRole.roleArn,
taskRoleArn: taskRole.roleArn,
cpu: '1024', // String instead of number
memory: '2048', // String instead of number
primaryContainer: {
image: 'public.ecr.aws/docker/library/nginx:latest',
containerPort: 80,
},
networkConfiguration: {
subnets: vpc.privateSubnets.map(subnet => subnet.subnetId), // Manual mapping
securityGroups: [securityGroup.securityGroupId],
},
healthCheckPath: '/',
});
```
**Issues with L1 approach:**
- Verbose ARN and ID mapping
- No validation or defaults
- String-based resource units (cpu, memory) instead of numbers
- No access to generated resources (ALB, target groups)
- Manual subnet and security group ID extraction
- No helper methods for common operations
### Benefits of L2 Construct
1. **Consistency** - Aligns with existing `Ec2Service` and `FargateService` patterns
2. **Type Safety** - Strong typing for all properties and return values
3. **Reduced Code** - Less boilerplate and manual configuration
4. **Better Integration** - Seamless integration with other CDK constructs
5. **Improved DX** - Better developer experience with autocomplete and validation
6. **Future-proof** - Room for Express-specific optimizations and features
### Related Issues
- Similar pattern established for `Ec2Service` and `FargateService`
- ECS Express Mode is a major new feature requiring first-class CDK support
- L2 constructs significantly improve developer experience over L1
### Acknowledgements
- ECS Express Mode was announced on November 21, 2025
- `CfnExpressGatewayService` was added in aws-cdk-lib v2.230.0
- Feature is available in all AWS regions
### Is this a CDK for Terraform (CDKTF) issue?
- [ ] I'm working with CDKTF in a language other than TypeScript.
---
### Environment
- **CDK CLI Version**: 2.1031.2
- **Module Version**: aws-cdk-lib@2.230.0
- **Node.js Version**: v24.11.1
- **OS**: Ubuntu 24.04
- **Language**: TypeScript
### Other
The introduction of L2 constructs for ECS Express Mode would significantly improve the developer experience and encourage adoption of this new AWS feature. The current L1-only approach limits the benefits of using CDK for infrastructure as code.
Contributor guide
Research direction
Start by reading the existing CfnExpressGatewayService L1 and comparing the established Ec2Service and FargateService patterns in aws-ecs. Define the supported ExpressGatewayService and optional task-definition API, then verify that the construct provides the proposed defaults, validation, integrations, generated-resource access, tests, documentation, and examples.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100