# Deno on AWS with SST

We are going to build an app with Deno, add an S3 Bucket for file uploads, and deploy it to AWS in a container with SST.

Before you get started, make sure to [configure your AWS credentials](https://sst.dev/docs/iam-credentials#credentials).

---

## 1. Create a project

Let’s start by creating our Deno app.

```
deno init aws-deno
```

---

### Init Deno Serve

Replace your `main.ts` with the following.

```
Deno.serve(async (req) => {

const url = new URL(req.url);

if (url.pathname === "/" && req.method === "GET") {

return new Response("Hello World!");

}

return new Response("404!");

});
```

This starts up an HTTP server by default on port `8000`.

---

### Init SST

Make sure you have [SST installed globally](https://sst.dev/docs/reference/cli).

```
sst init
```

This’ll create an `sst.config.ts` file in your project root.

---

## 2. Add a Service

To deploy our Deno app, let’s add an [AWS Fargate](https://aws.amazon.com/fargate/) container with [Amazon ECS](https://aws.amazon.com/ecs/). Update your `sst.config.ts`.

```
async run() {

const vpc = new sst.aws.Vpc("MyVpc");

const cluster = new sst.aws.Cluster("MyCluster", { vpc });

new sst.aws.Service("MyService", {

cluster,

loadBalancer: {

ports: [{ listen: "80/http", forward: "8000/http" }],

},

dev: {

command: "deno task dev",

},

});

}
```

This creates a VPC with an ECS Cluster, and adds a Fargate service to it.
The `dev.command` tells SST to instead run our Deno app locally in dev mode.

---

### Start dev mode

Run the following to start dev mode. This’ll start SST and your Deno app.

```
sst dev
```

Once complete, click on **MyService** and open your Deno app in your browser.

---

## 3. Add an S3 Bucket

Let’s add an S3 Bucket for file uploads. Add this to your `sst.config.ts` below the `Vpc` component.

```
const bucket = new sst.aws.Bucket("MyBucket");
```

---

### Link the bucket

Now, link the bucket to the container.

```
new sst.aws.Service("MyService", {

// ...

link: [bucket],

});
```

This will allow us to reference the bucket in our Deno app.

---

## 4. Upload a file

We want a `POST` request made to the `/` route to upload a file to our S3 bucket. Let’s add this below our _Hello World_ route in our `main.ts`.

```
if (url.pathname === "/" && req.method === "POST") {

const formData: FormData = await req.formData();

const file: File | null = formData?.get("file") as File;

const params = {

Bucket: Resource.MyBucket.name,

ContentType: file.type,

Key: file.name,

Body: file,

};

const upload = new Upload({

params,

client: s3,

});

await upload.done();

return new Response("File uploaded successfully.");
}
```

Add the imports. We’ll use the extra ones below.

```
import { Resource } from "sst";
import {

S3Client,

GetObjectCommand,

ListObjectsV2Command,

} from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client();
```

And install the npm packages.

```
deno install npm:sst npm:@aws-sdk/client-s3 npm:@aws-sdk/lib-storage npm:@aws-sdk/s3-request-presigner
```

---

## 5. Download the file

We’ll add a `/latest` route that’ll download the latest file in our S3 bucket. Let’s add this below our upload route in `main.ts`.

```
if (url.pathname === "/latest" && req.method === "GET") {

const objects = await s3.send(

new ListObjectsV2Command({

Bucket: Resource.MyBucket.name,

}),

);

const latestFile = objects.Contents!.sort(

(a, b) =>

(b.LastModified?.getTime() ?? 0) - (a.LastModified?.getTime() ?? 0),

)[0];

const command = new GetObjectCommand({

Key: latestFile.Key,

Bucket: Resource.MyBucket.name,

});

return Response.redirect(await getSignedUrl(s3, command));
}
```

---

### Test your app

To upload a file run the following from your project root. You might have to go to the `MyService` tab and accept the Deno permission prompts.

```
curl -F file=@deno.json http://localhost:8000/
```

This should upload the `deno.json`. Now head over to `http://localhost:8000/latest` in your browser and it’ll show you what you just uploaded.

---

## 6. Deploy your app

To deploy our app we’ll first add a `Dockerfile`.

```
FROM denoland/deno

EXPOSE 8000

USER deno

WORKDIR /app

ADD . /app

RUN deno install --entrypoint main.ts

CMD ["run", "--allow-all",  "main.ts"]
```

Now to build our Docker image and deploy we run:

```
sst deploy --stage production
```

You can use any stage name here but it’s good to create a new stage for production. This’ll give the URL of your Deno app deployed as a Fargate service.

```
✓  Complete

MyService: http://prod-MyServiceLoadBalanc-491430065.us-east-1.elb.amazonaws.com
```

---

## Connect the console

As a next step, you can setup the [SST Console](https://sst.dev/docs/console/) to git push to deploy your app and view logs from it.

You can [create a free account](https://console.sst.dev/) and connect it to your AWS account.
