Understanding AWS Fargate
AWS Fargate is a serverless compute engine for containers that works with both Amazon ECS and Amazon EKS. It abstracts away the underlying EC2 instances so you no longer need to provision, scale, or manage clusters of virtual machines. You simply define the CPU, memory, networking, and IAM policies required by your containers, and Fargate handles the infrastructure on your behalf.
Why it matters: Fargate eliminates the operational burden of managing host clusters, improves security isolation by giving each task its own dedicated execution environment, and enables precise cost allocation at the task level. It’s particularly well-suited for microservices, scheduled batch jobs, and event-driven workloads that need to scale quickly without the overhead of managing servers.
How Fargate Works
When you launch a container on Fargate, you provide a task definition that specifies the vCPU and memory combination, the container image, environment variables, secrets, logging configuration, and networking details. Fargate automatically provisions the required compute resources, attaches an Elastic Network Interface (ENI) to each task, and ensures the task runs in its own secure sandbox. Billing is calculated per second based on the vCPU and memory you allocate, with a one-minute minimum charge. Fargate also offers a Fargate Spot option for interruptible workloads at up to a 70% discount compared to standard Fargate pricing.
Now that you understand the basics, let’s dive into concrete best practices that will help you optimize cost, security, and performance across your Fargate workloads.
Cost Optimization Best Practices
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Right-Sizing Task Resources
Over-provisioning CPU or memory is the most common source of Fargate waste. Fargate charges you for the resources you specify in the task definition, not for actual usage. Use monitoring tools like AWS CloudWatch Container Insights to observe actual CPU and memory utilization over time, then adjust your task definitions accordingly. Always start with the smallest viable vCPU/memory combination and scale up only when performance data justifies it.
A typical task definition snippet with a moderate resource allocation looks like this:
{
"family": "my-service",
"taskRoleArn": "arn:aws:iam::123456789012:role/MyTaskRole",
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "app",
"image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
"cpu": 256,
"memory": 512,
"essential": true,
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
]
}
],
"cpu": "256",
"memory": "512"
}
In this example, the task receives 256 CPU units (0.25 vCPU) and 512 MB of memory. Always match the container-level cpu and memory values to the task-level ones unless you have a multi-container task that needs a different split.
Leveraging Fargate Spot
Fargate Spot tasks are ideal for stateless, fault-tolerant, or time-insensitive workloads such as CI/CD runners, data processing jobs, or development environments. They can be reclaimed by AWS with a two-minute warning, so your application must be designed to handle interruptions gracefully. To use Spot, create a capacity provider strategy that mixes Spot and standard Fargate.
Example CloudFormation snippet for a mixed strategy:
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 2
CapacityProviderStrategy:
- CapacityProvider: FARGATE_SPOT
Weight: 1
- CapacityProvider: FARGATE
Weight: 0
NetworkConfiguration:
AwsvpcConfiguration:
Subnets: !Ref Subnets
SecurityGroups: !Ref SecurityGroup
AssignPublicIp: DISABLED
With this configuration, all tasks will initially launch on Fargate Spot because the weight for FARGATE is 0. Adjust weights to blend on-demand and Spot capacity as needed.
Compute Savings Plans and Reserved Capacity
If you run predictable workloads on Fargate, consider purchasing a Compute Savings Plan. These plans offer discounts of up to 66% in exchange for a one- or three-year commitment of consistent usage, measured in dollars per hour. They automatically apply to any Fargate usage across regions and accounts, making them extremely flexible. For steady-state production services, this can dramatically reduce your monthly bill.
Choosing the Right CPU Architecture
AWS Graviton processors (ARM64) are available for Fargate and often deliver better price-performance for a wide variety of workloads, including web apps, microservices, and data analytics. Switching from x86 to ARM can yield up to 20% cost savings. Specify the architecture in the task definition’s runtimePlatform field:
{
"family": "my-graviton-service",
"runtimePlatform": {
"cpuArchitecture": "ARM64",
"operatingSystemFamily": "LINUX"
},
"cpu": "256",
"memory": "512",
...
}
Verify that your container images support ARM (multi-arch images or dedicated ARM tags) before switching.
Monitoring and Tracking Costs
Enable the Cost Allocation Tags feature and tag all Fargate services with environment, team, or application identifiers. Use AWS Cost Explorer and AWS Budgets to set alerts and visualize spending patterns. Regularly review the AWS Fargate Cost and Usage Report (CUR) to identify outliers and adjust resources or architecture accordingly.
Security Best Practices
IAM Task Roles and Least Privilege
Every Fargate task should have its own IAM role (taskRoleArn) that grants precisely the permissions the container needs to interact with AWS services (e.g., S3, DynamoDB, SQS). Avoid reusing roles across unrelated services. The executionRoleArn is separate and is used by the ECS agent to pull images from ECR and send logs to CloudWatch; keep it minimal as well.
Example IAM policy for a task role that allows read-only access to a specific S3 bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-bucket",
"arn:aws:s3:::my-app-bucket/*"
]
}
]
}
Attach this policy to the task role and reference that role in the task definition’s taskRoleArn field.
Secrets Management
Never bake secrets into container images or environment variables. Use AWS Secrets Manager or Systems Manager Parameter Store (SecureString) to store credentials, API keys, and database connection strings. Reference them in your container definition using the secrets block:
"containerDefinitions": [
{
"name": "app",
"image": "my-app",
"secrets": [
{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db-password"
},
{
"name": "API_KEY",
"valueFrom": "arn:aws:ssm:us-east-1:123456789012:parameter/my-app/api-key"
}
]
}
]
Ensure the task execution role has permissions to read the specific secret or parameter. Fargate automatically injects these values as environment variables into the container at startup.
Network Security
Place Fargate tasks in a VPC with private subnets (no direct internet access) unless you explicitly need a public IP. Use security groups to strictly control inbound and outbound traffic. For services exposed via an Application Load Balancer (ALB), only allow traffic from the ALB security group on the container port.
Example security group definition for a Fargate service behind an ALB:
TaskSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow traffic from ALB to Fargate task
VpcId: !Ref VpcId
SecurityGroupIngress:
- SourceSecurityGroupId: !Ref LoadBalancerSecurityGroup
IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 443
ToPort: 443
Description: Allow outbound HTTPS to internet
Restrict egress to only the destinations your application truly needs (e.g., specific APIs, S3 prefixes via VPC endpoints). This limits data exfiltration risks.
Image Security
Scan your container images regularly using Amazon ECR’s built-in image scanning or integration with tools like Docker Scout or Trivy. Enable scanOnPush in your ECR repository to automatically inspect images for vulnerabilities when they are pushed. Use signed images with AWS Signer to enforce that only trusted images run in your tasks. Avoid the :latest tag in production; pin to a specific digest or immutable tag.
Logging and Auditing
Send container logs to CloudWatch Logs and enable encryption. Use FireLens, Fargate’s built-in log router, to forward logs directly to services like Amazon OpenSearch, S3, or external SIEMs without sidecar containers. Configure the log driver in your container definition:
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "my-service-logs",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "fargate",
"awslogs-create-group": "true"
}
}
Enable AWS CloudTrail to audit all ECS/Fargate API calls and combine with GuardDuty for threat detection on your Fargate tasks.
Platform Version and Isolation
Always use the LATEST platform version (currently version 1.4.0 or higher). This ensures you receive the latest security patches and the improved task isolation that provides a dedicated runtime environment per task. Older platform versions may lack certain features and hardening. In the ECS service or task definition, you can specify platformVersion as LATEST (though it defaults to LATEST unless overridden).
Performance Best Practices
Choosing Optimal CPU and Memory Combinations
Fargate offers predefined vCPU/memory ratios, but you should select based on your workload profile. CPU-bound applications (e.g., video encoding, machine learning inference) benefit from higher vCPU allocations, while memory-caching workloads need more RAM. Avoid the minimum 256 vCPU for anything that handles concurrent requests; 512 vCPU (0.5 vCPU) with 1024 MB memory is a common starting point for lightweight web services.
Use CloudWatch Container Insights to monitor CpuUtilized and MemoryUtilized. If you consistently see high utilization near the limit, scale up the task size. For bursty workloads, consider splitting tasks into smaller units and scaling out horizontally instead of scaling up vertically.
Container Image Optimization
Large container images slow down startup time and increase the cold-start latency that can affect responsiveness, especially during scaling events. Apply the following techniques:
- Use multi-stage builds to keep final images slim.
- Leverage AWS provided base images (e.g., ECR Public Gallery) that are optimized for Fargate.
- Remove unnecessary packages, cache layers, and temporary build artifacts.
- Store images in Amazon ECR in the same region as your Fargate tasks to reduce pull latency.
Health Checks and Graceful Shutdowns
Configure container health checks so that Fargate can detect stuck processes and replace them automatically. Define a healthCheck block in your container definition that matches your application’s readiness logic:
"healthCheck": {
"command": ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 60
}
Also set a stopTimeout (default is 30 seconds) to allow the container to drain connections or finish in-flight work before being forcibly terminated. In the task definition:
"stopTimeout": 120
Service Connect for Microservices
AWS ECS Service Connect provides a service mesh that enables secure, low-latency communication between Fargate services without requiring sidecar proxies or additional code. It leverages Cloud Map for service discovery and automatically distributes traffic across healthy endpoints. Enable it in your ECS service definition to improve resilience and reduce cross-service latency:
ServiceConnectConfiguration:
Enabled: true
Namespace: !Ref CloudMapNamespace
Services:
- PortName: my-port
DiscoveryName: my-service-discovery
ClientAliases:
- Port: 8080
Service Connect also integrates with AWS Distro for OpenTelemetry to collect traces and metrics.
Monitoring and Observability
Enable Container Insights for detailed performance metrics including CPU, memory, network, and disk utilization per task. You can turn it on at the cluster level via CloudFormation or the console. In CloudFormation, set the ClusterSettings property:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterSettings:
- Name: containerInsights
Value: enabled
Pair Container Insights with AWS Distro for OpenTelemetry (ADOT) to collect distributed traces across Fargate services. Use an ADOT sidecar or the built-in integration with CloudWatch to capture request flows and identify bottlenecks.
Using EFS for Persistent Storage
Fargate tasks are ephemeral by nature. When stateful workloads need durable storage that survives task restarts, mount an Amazon EFS file system as a volume. This is useful for content management systems, CI/CD workspace caching, or shared application state. Define the volume and mount point in your task definition:
"volumes": [
{
"name": "efs-storage",
"efsVolumeConfiguration": {
"fileSystemId": "fs-12345678",
"rootDirectory": "/data",
"transitEncryption": "ENABLED",
"authorizationConfig": {
"iam": "ENABLED"
}
}
}
],
"containerDefinitions": [
{
"name": "app",
"mountPoints": [
{
"sourceVolume": "efs-storage",
"containerPath": "/mnt/data"
}
]
}
]
Ensure the task role has the necessary elasticfilesystem permissions. Enable transit encryption and IAM authorization to maintain security while gaining persistent performance.
Conclusion
Fargate removes the complexity of managing container hosts, but to fully realize its benefits you need to treat cost, security, and performance as interconnected pillars. Right-size your resources and leverage Fargate Spot and Savings Plans to keep costs in check. Enforce least-privilege IAM roles, network segmentation, secrets encryption, and image scanning to harden your deployments. Optimize task sizes, images, health checks, and observability tooling to deliver responsive, reliable services. By continuously measuring and iterating on these best practices, you can build a robust, cost-effective, and secure container architecture that scales effortlessly on AWS Fargate.