Skip to main content
On this page

Deploy Deno to AWS ECS Fargate

AWS Fargate is a serverless compute engine for containers that works with Amazon Elastic Container Service (ECS). You package your app as a container image, hand ECS a task definition, and Fargate provisions and scales the underlying compute for you, so there are no EC2 instances to manage.

This tutorial walks through containerizing a Deno app, pushing the image to Amazon ECR, and running it as a Fargate service.

Before continuing, make sure you have:

Create the app and Dockerfile Jump to heading

To keep the focus on deployment, our app is a single main.ts that serves an HTTP response:

main.ts
Deno.serve({ port: 8000 }, () => new Response("Hello from Deno on Fargate!"));

Next to it, add a Dockerfile:

Dockerfile
FROM denoland/deno

EXPOSE 8000

WORKDIR /app

ADD . /app

RUN deno install --entrypoint main.ts

CMD ["run", "--allow-net", "main.ts"]

Test it locally before deploying:

docker build -t deno-fargate .
docker run -p 8000:8000 deno-fargate

Visit localhost:8000 and you should see the response. Fargate requires linux/amd64 images unless you create an ARM task, so if you are on an Apple Silicon machine build for that platform when you push:

docker build --platform linux/amd64 -t deno-fargate .

Push the image to Amazon ECR Jump to heading

Set a couple of shell variables for convenience, replacing the values with your account ID and preferred region:

export AWS_ACCOUNT_ID=123456789012
export AWS_REGION=us-east-1
export REPO=deno-fargate

Create an ECR repository to hold the image:

aws ecr create-repository --repository-name $REPO --region $AWS_REGION

Authenticate Docker with ECR, then tag and push the image:

aws ecr get-login-password --region $AWS_REGION \
  | docker login --username AWS --password-stdin \
    $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

docker tag deno-fargate \
  $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO:latest

docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$REPO:latest

Create a task definition Jump to heading

A task definition tells ECS how to run your container: which image, how much CPU and memory, and which ports to expose. Save the following as task-definition.json, substituting your account ID and region:

task-definition.json
{
  "family": "deno-fargate",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "deno-fargate",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/deno-fargate:latest",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 8000,
          "protocol": "tcp"
        }
      ]
    }
  ]
}

The executionRoleArn refers to the ecsTaskExecutionRole, which lets ECS pull images from ECR and write logs to CloudWatch. If you have not used ECS before, create it once by following the AWS guide.

Register the task definition:

aws ecs register-task-definition \
  --cli-input-json file://task-definition.json \
  --region $AWS_REGION

Run it as a Fargate service Jump to heading

Create a cluster to hold the service:

aws ecs create-cluster --cluster-name deno-cluster --region $AWS_REGION

Now create a service that keeps one copy of the task running. Fargate needs to know which subnets and security group to launch into, and assignPublicIp lets the task pull the image and be reachable without a NAT gateway. Replace the subnet and security group IDs with ones from your VPC, and make sure the security group allows inbound traffic on port 8000:

aws ecs create-service \
  --cluster deno-cluster \
  --service-name deno-fargate \
  --task-definition deno-fargate \
  --desired-count 1 \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[subnet-abc123],securityGroups=[sg-abc123],assignPublicIp=ENABLED}" \
  --region $AWS_REGION

Once the service reaches a steady state, find the task's public IP:

TASK_ARN=$(aws ecs list-tasks --cluster deno-cluster \
  --service-name deno-fargate --query "taskArns[0]" --output text --region $AWS_REGION)

ENI_ID=$(aws ecs describe-tasks --cluster deno-cluster --tasks $TASK_ARN \
  --query "tasks[0].attachments[0].details[?name=='networkInterfaceId'].value" \
  --output text --region $AWS_REGION)

aws ec2 describe-network-interfaces --network-interface-ids $ENI_ID \
  --query "NetworkInterfaces[0].Association.PublicIp" --output text --region $AWS_REGION

Open http://<public-ip>:8000 and you should see your Deno app responding from Fargate.

Production considerations Jump to heading

For anything beyond a demo, put the service behind an Application Load Balancer instead of exposing the task's public IP directly. The load balancer gives you a stable DNS name, TLS termination, and health checks, and it lets ECS roll new deployments without downtime. You can also raise desired-count to run multiple tasks and enable service auto scaling to adjust capacity based on load.

🦕 Now you can deploy a Deno app to AWS ECS Fargate by containerizing it, pushing the image to Amazon ECR, and running it as a Fargate service.

Last updated on

Did you find what you needed?

Edit this page
Privacy policy