Solve: Teaching SAM to Share—Splitting template.yaml into Multiple Files
Solve: Teaching SAM to Share—Splitting template.yaml into Multiple Files
A cloud
engineer working in a growing team project recently ran into a small but
familiar problem. Their AWS SAM project had ballooned into a single, unwieldy
template.yaml file. At first it was fine—just a function or two, an API
definition, maybe a table. But weeks later, with new teammates and added
resources, the file had become a cluttered wall of YAML. The engineer didn’t
want to migrate away from SAM, but they did want a way to split things up.
“Can I just divide this into multiple files somehow?” they asked.
That’s a fair question. SAM doesn’t support this directly—unlike Terraform or CDK—but with a little shell script magic and one or two external tools, you can absolutely get there. The trick is not to fight SAM’s single-template expectation head-on, but instead to preprocess your own clean, modular YAML structure into a single file right before deploying.
There are two practical ways to approach this. The first involves using a YAML-aware tool like yq to stitch smaller files together before calling sam deploy. The second uses a simpler design principle: keep the SAM template flat, but externalize everything else that changes often. Either way, the goal is the same—cleaner structure, calmer development.
Why SAM Doesn’t Support This Out of the Box
When you first start using AWS SAM, it’s easy to assume that breaking your infrastructure into smaller, reusable files would be standard practice. After all, tools like Terraform and CDK encourage modular design from day one. But SAM’s foundation is CloudFormation, and CloudFormation was built around a single-template model—a master document that lays out the entire infrastructure stack in one go.
This design works well for deploying infrastructure in a predictable, immutable fashion. But it also means there’s no built-in syntax like include, import, or require that would let you split Resources or Outputs across multiple files. SAM inherits this behavior and adds its own layer of abstraction for serverless applications, but that core limitation remains.
So when your template.yaml grows beyond a few resources, you're left with a choice: either wrangle with a giant file that keeps getting longer, or explore ways to stitch together smaller pieces yourself before deployment. There’s nothing wrong with the monolithic approach per se—it’s just not designed for the way most teams work in the real world. Shared ownership, onboarding, and quick iterations all become harder when one file controls the entire infrastructure conversation.
That’s where the workarounds come in. With a little help from common CLI tools and a touch of shell scripting, you can introduce the modularity SAM forgot—without switching stacks, abandoning best practices, or rewriting your whole project.
Approach 1: Preprocess with yq or a Custom Script
If AWS SAM expects a single template.yaml file, the obvious workaround is to build that file yourself—just before deployment. You can organize your infrastructure definitions in smaller, topic-based files, and then stitch them together using a pre-deploy script. This way, your working directory stays clean and maintainable, while SAM still gets the one flat file it requires.
Here’s a simple folder structure that works well:
Each file defines just one part of the stack: API routes in api.yaml, Lambda functions in lambdas.yaml, and so on. At deploy time, you use a YAML-aware tool like yq (the Go-based version, not the Python one) to merge them into a complete template.yaml.
Here’s a lightweight stitch.sh example:
You can add this to a Makefile or CI step, and now your repo is modular without needing to switch away from SAM. The benefit here is that your team can focus on specific parts of the infrastructure without constantly tripping over each other in a giant file.
There’s one important note: this method assumes each YAML fragment uses the correct nesting. That means your resources/api.yaml file should begin with Resources: at the root. These are real SAM components—just distributed for clarity. If you prefer more control, you can merge specific sections (Resources, Outputs, etc.) independently and wrap them yourself in the final file.
Approach 2: Treat SAM as Immutable, Externalize Everything Else
If you'd rather not introduce a pre-processing step, there’s another way to ease the burden of a growing template.yaml: keep it monolithic, but push everything else out. Instead of trying to split the template, you treat it as a stable interface—and move all the volatile, fast-changing content into external files and folders. It’s not true modularization, but it does wonders for your workflow.
In practice, this means your SAM template references code and configurations that live elsewhere:
Function code lives in its own folder:
API definitions are moved to standalone OpenAPI specs:
Environment variables and parameter values are loaded from
samconfig.toml, params.json, or .env files.
The result? Your template.yaml might still be long—but it’s calm. It stops being the battleground for change and becomes a steady, predictable interface that developers touch less often. Meanwhile, changes to business logic, routes, or configuration files can happen in isolation. You onboard faster. You reduce conflicts. And your CI/CD pipelines don’t get tangled up in constant YAML churn.
This approach pairs beautifully with Git: the template rarely changes, while individual contributors work in their own slices of the repo. For many teams, this is all they need. No merging. No stitching. Just a steady file and some good folder hygiene.
It’s not modularization in the purist sense—but it makes SAM much more livable.
What About AWS::Serverless::Application?
You might be wondering—doesn’t AWS SAM have an official way to break things up? The answer is yes, technically. SAM supports nested stacks using the AWS::Serverless::Application resource. This lets you reference another SAM template as a self-contained application component, typically hosted in S3 or a public repository.
It's a powerful tool when used as intended: to reuse pre-packaged infrastructure like a login service, notification engine, or microservice bundle. You pass in parameters, hook up outputs, and stack it like building blocks. For organizations that maintain central modules or want stricter deployment boundaries, this approach can be a great fit.
But here’s the thing—it’s not designed for day-to-day YAML cleanup. Each nested application must be packaged, uploaded, versioned, and stored in a way SAM can resolve at build or deploy time. That’s a lot of ceremony when your goal is simply to organize your growing template.yaml.
If you're building reusable infrastructure components across multiple projects or teams, AWS::Serverless::Application is the official path.
But if you're just trying to get through your day without scroll fatigue, you may find that a yq-based stitching script or structured file layout gets you further, faster.
Final Thoughts: Small Tricks, Big Impact
When you're deep in a project, sometimes it’s not the cloud that wears you down—it’s the file structure. You’re trying to move quickly, share work with a team, and avoid merge conflicts… and yet here comes template.yaml, growing by the week, demanding scrolls and squints and careful line-by-line surgery.
The truth is, SAM wasn’t built to scale gracefully in the developer ergonomics department. It assumes one file, one deployable unit, and one path to structure. But real-world projects aren’t that tidy. Fortunately, with a little discipline and a few helpful tools, you can create the structure you need without fighting the platform.
Whether you choose to preprocess modular fragments with yq, or simply externalize your API specs, Lambda code, and parameters into well-organized folders, the result is the same: sanity restored. And the best part? You’re not breaking compatibility with SAM—you’re extending it in a way that suits how real teams build, debug, and deliver.
If there’s interest, we may share a small CLI tool that automates the stitching process. For now, though, a shell script and a little planning go a long way. As with most things in AWS, the hardest part isn’t the cloud—it’s the glue between people, process, and plain text files.
That’s a fair question. SAM doesn’t support this directly—unlike Terraform or CDK—but with a little shell script magic and one or two external tools, you can absolutely get there. The trick is not to fight SAM’s single-template expectation head-on, but instead to preprocess your own clean, modular YAML structure into a single file right before deploying.
There are two practical ways to approach this. The first involves using a YAML-aware tool like yq to stitch smaller files together before calling sam deploy. The second uses a simpler design principle: keep the SAM template flat, but externalize everything else that changes often. Either way, the goal is the same—cleaner structure, calmer development.
Why SAM Doesn’t Support This Out of the Box
When you first start using AWS SAM, it’s easy to assume that breaking your infrastructure into smaller, reusable files would be standard practice. After all, tools like Terraform and CDK encourage modular design from day one. But SAM’s foundation is CloudFormation, and CloudFormation was built around a single-template model—a master document that lays out the entire infrastructure stack in one go.
This design works well for deploying infrastructure in a predictable, immutable fashion. But it also means there’s no built-in syntax like include, import, or require that would let you split Resources or Outputs across multiple files. SAM inherits this behavior and adds its own layer of abstraction for serverless applications, but that core limitation remains.
So when your template.yaml grows beyond a few resources, you're left with a choice: either wrangle with a giant file that keeps getting longer, or explore ways to stitch together smaller pieces yourself before deployment. There’s nothing wrong with the monolithic approach per se—it’s just not designed for the way most teams work in the real world. Shared ownership, onboarding, and quick iterations all become harder when one file controls the entire infrastructure conversation.
That’s where the workarounds come in. With a little help from common CLI tools and a touch of shell scripting, you can introduce the modularity SAM forgot—without switching stacks, abandoning best practices, or rewriting your whole project.
Approach 1: Preprocess with yq or a Custom Script
If AWS SAM expects a single template.yaml file, the obvious workaround is to build that file yourself—just before deployment. You can organize your infrastructure definitions in smaller, topic-based files, and then stitch them together using a pre-deploy script. This way, your working directory stays clean and maintainable, while SAM still gets the one flat file it requires.
Here’s a simple folder structure that works well:
Each file defines just one part of the stack: API routes in api.yaml, Lambda functions in lambdas.yaml, and so on. At deploy time, you use a YAML-aware tool like yq (the Go-based version, not the Python one) to merge them into a complete template.yaml.
Here’s a lightweight stitch.sh example:
You can add this to a Makefile or CI step, and now your repo is modular without needing to switch away from SAM. The benefit here is that your team can focus on specific parts of the infrastructure without constantly tripping over each other in a giant file.
There’s one important note: this method assumes each YAML fragment uses the correct nesting. That means your resources/api.yaml file should begin with Resources: at the root. These are real SAM components—just distributed for clarity. If you prefer more control, you can merge specific sections (Resources, Outputs, etc.) independently and wrap them yourself in the final file.
Approach 2: Treat SAM as Immutable, Externalize Everything Else
If you'd rather not introduce a pre-processing step, there’s another way to ease the burden of a growing template.yaml: keep it monolithic, but push everything else out. Instead of trying to split the template, you treat it as a stable interface—and move all the volatile, fast-changing content into external files and folders. It’s not true modularization, but it does wonders for your workflow.
In practice, this means your SAM template references code and configurations that live elsewhere:
Function code lives in its own folder:
The result? Your template.yaml might still be long—but it’s calm. It stops being the battleground for change and becomes a steady, predictable interface that developers touch less often. Meanwhile, changes to business logic, routes, or configuration files can happen in isolation. You onboard faster. You reduce conflicts. And your CI/CD pipelines don’t get tangled up in constant YAML churn.
This approach pairs beautifully with Git: the template rarely changes, while individual contributors work in their own slices of the repo. For many teams, this is all they need. No merging. No stitching. Just a steady file and some good folder hygiene.
It’s not modularization in the purist sense—but it makes SAM much more livable.
What About AWS::Serverless::Application?
You might be wondering—doesn’t AWS SAM have an official way to break things up? The answer is yes, technically. SAM supports nested stacks using the AWS::Serverless::Application resource. This lets you reference another SAM template as a self-contained application component, typically hosted in S3 or a public repository.
It's a powerful tool when used as intended: to reuse pre-packaged infrastructure like a login service, notification engine, or microservice bundle. You pass in parameters, hook up outputs, and stack it like building blocks. For organizations that maintain central modules or want stricter deployment boundaries, this approach can be a great fit.
But here’s the thing—it’s not designed for day-to-day YAML cleanup. Each nested application must be packaged, uploaded, versioned, and stored in a way SAM can resolve at build or deploy time. That’s a lot of ceremony when your goal is simply to organize your growing template.yaml.
If you're building reusable infrastructure components across multiple projects or teams, AWS::Serverless::Application is the official path.
But if you're just trying to get through your day without scroll fatigue, you may find that a yq-based stitching script or structured file layout gets you further, faster.
Final Thoughts: Small Tricks, Big Impact
When you're deep in a project, sometimes it’s not the cloud that wears you down—it’s the file structure. You’re trying to move quickly, share work with a team, and avoid merge conflicts… and yet here comes template.yaml, growing by the week, demanding scrolls and squints and careful line-by-line surgery.
The truth is, SAM wasn’t built to scale gracefully in the developer ergonomics department. It assumes one file, one deployable unit, and one path to structure. But real-world projects aren’t that tidy. Fortunately, with a little discipline and a few helpful tools, you can create the structure you need without fighting the platform.
Whether you choose to preprocess modular fragments with yq, or simply externalize your API specs, Lambda code, and parameters into well-organized folders, the result is the same: sanity restored. And the best part? You’re not breaking compatibility with SAM—you’re extending it in a way that suits how real teams build, debug, and deliver.
If there’s interest, we may share a small CLI tool that automates the stitching process. For now, though, a shell script and a little planning go a long way. As with most things in AWS, the hardest part isn’t the cloud—it’s the glue between people, process, and plain text files.
* * *
Written by Aaron Rose, software engineer and technology writer at Tech-Reader.blog.
Comments
Post a Comment