Practical Appsync + Cognito for Single-Page Applications


If you want to get new-agey and deploy a GraphQL API in a serverless architecture, what’s the best way? You can make that work with API Gateway but it’s a little cludgey and normally results in implementing a super Lambda function that contains all your GraphQL resolver logic.

Lucky us! AWS has a GraphQL specific API proxy called AppSync. Last month, I did an article overviewing AppSync and concluded I would try it out on an upcoming project. Well dear reader, I have done it and now I am bringing you my results!

Starting with AWS Amplify

AWS Amplify is a cool project with a lot of potential. It’s made up of several different projects:

(I may have the naming scheme wrong; but it seems correct to me)

The Amplify framework is a great set of libraries. It offers you clients for AppSync, Cognito, and more. The AppSync client it provides is also compatible with the popular Apollo project. Amplify Framework and Amplify CLI are often used hand-in-hand. The Amplify console is purely optional, but a nice addition for automated deploys.

Out-of-the-box, the CLI tool gives you a lot:

One thing to note, everytime I setup both Amplify Console and CLI hosting resources, they deployed to different S3 buckets. Not sure if that’s always the case or I just missed something.

Overall, Amplify really is an awesome project and provided an excellent dev/test environment for me to quickly iterate and experiment with AppSync and Cognito.

(there’s a but coming)


Amplify CLI has a few edge cases that are either really annoying OR are missing and really important for production applications.

A lot of these things will be addressed as Amplify continues to mature, I have no doubt.

I also don’t fault Amplify team for using Cloudformation because (a) they work at Amazon, (b) it stores all state in AWS be default which is easy for tool providers, and (c) rollbacks can be nice. But my personal goal is to use Cloudformation as little as possible. Small doses, it’s fine. Big doses, annoying AF.

Replacing Amplify for Production

For using Cognito and AppSync in the client, I still use the Amplify JS libraries which are quite awesome.

Then, using the Cloudformation tempates generated by Amplify CLI as a guide, I re-implemented them in terraform! For Lambda functions, I used serverless! Lucky for me, it only took me an afternoon to accomplish the entire switch!

Here is a link to my example repository:

My terraform scripts are in terraform/ and the resources are organized thusly:

  1. Variables, Outputs, and Data resources
  2. DynamoDB; AppSync API, Data Sources, and Resolvers; IAM perms
  3. Cognito Identity Pool, User Pool, User Groups, Clients, and IAM roles
  4. S3 website bucket, CloudFront distribution, Route 53 Record

Serverless functions are in services/. The code is just a dummy example. The serverless.yml however shows a few useful examples:

  1. Giving access to DynamoDB tables
  2. Outputting your function ARNs so you can plug them into terraform as variables

When using the terraform scripts in a non-toy app, I create multiple terraform workspaces and separate <stage>.tfvars files for use with each. Not beautiful, but works.

Upsides of this approach:

This approach is not without it’s downsides however. The main ones are (a) losing the CLI code generation features and (b) losing automagic CI/CD with the Amplify Console.

Those downsides acknowledged, I am still really enjoying this approach.


AppSync and Cognito are really awesome for frontend development projects. For quickly experimenting with them in a project, I recommend using AWS Amplify. But when the day comes to ship a product, you don’t have to give up control and predictability. You can take your same client code and, without much work, roll it over to terraform + serverless!

comments powered by Disqus