I'm Matt Bidewell
A software engineer in London 👨💻
Short: Using AWS Sam incorrectly.
I've been using the Sam CLI for the past 10 months. It's great at deploying multiple resources onto AWS and managing local deployments for cloud-based architecture.
I specifically use it in monorepos where the source code for multiple Lambda functions exists. These Lambdas are written in different languages. Initially, one monorepo started with Java and over time, Lambda functions written in Typescript were added.
We would use the following commands to deploy to AWS:
sam build -t infrastructure/lambda/template.yaml sam deploy -t infrastructure/lambda/template.yaml
template.yaml file was stored in the appropriately named
infrastructure directory we would need to use the
-t flag to specify the template to build and deploy.
The template.yaml file is the file that contains the Infrastructure as Code (IaC) that is created during deployment. In AWS Sam world, this is Cloudformation.
The template file looked something akin to this
Globals: Function: Architectures: - arm64 JavaFunction: Runtime: java11 Type: AWS::Serverless::Function Properties: CodeUri: ../../lambdas/JavaFunction Handler: build/handler.JavaHandler::handleRequest TypescriptFunction: Runtime: nodejs16.x Type: AWS::Serverless::Function Properties: Handler: app.lambdaHandler CodeUri: ../../lambdas/TypescriptFunction Metadata: # Manage esbuild properties BuildMethod: esbuild BuildProperties: Minify: true Target: "es2020" EntryPoints: - src/app.ts
When we added the initial Typescript lambda to the project, we found that deploying a simple
Hello World application to Lambda would result in the non-compiled code being deployed. Strange, this made no sense as AWS Sam is supposed to build and deploy the compiled code. Was it ESBuild? Sam CLI? Cloudformation?
I was able to reproduce it in a new repo and on other stacks, the result was always the same. It would deploy raw Typescript but also the compiled Java.
The problem was the
-t flag in the deploy command. When
sam build ... runs, it creates a directory called
.aws-sam which then holds all the compiled code. Whats important is that
sam build also creates a new
template.yaml file in that directory with updated codeUri paths.
├── .aws-sam/ <This is created by AWS Sam> │ ├─ template.yaml <created by AWS Sam CLI> └─<Compiled lambda code> ├── ... ├── infrastructure/ │ ├── lambda/ │ └── template.yaml ├── src/ │ └── <function> │ ├── <function code>
Theres a note added the AWS Sam documentation under the
-t flag that states.
-t,--template-file The path and file name where your AWS SAM template is located. Note: If you specify this option, then AWS SAM deploys only the template and the local resources that it points to.
The key line to note is it deploys the local resources that it points to. In our use case, it was deploying the directories that we were working in. The Java code was in a build directory in the source folders, so we never saw an issue. (unless you tried to deploy without building your code manually 🚩😬 which should have been a massive hint)
By omitting the
-t from our deploy step, AWS Sam will now correctly build from the directory IT has built the files in, default
RTFM. Situations like this are a clear indicator of why we should spend more time reading the documentation and not always diving straight in. It's also good to remember to make sure you're using the tool correctly.