Yan Cui
I help clients go faster for less using serverless technologies.
This article is brought to you by
Don’t reinvent the patterns. Catalyst gives you consistent APIs for messaging, data, and workflow with key microservice patterns like circuit-breakers and retries for free.
Sharing code efficiently across different parts of an application can be challenging with AWS Lambda, especially when using Amplify. Today, I’ll walk you through a solution to this common problem, without relying on Lambda Layers or private NPM repositories.
The Context
In my previous post about Lambda Layers [1], I delved into its limitations, especially when compared with traditional package managers like NPM. For most use cases, Lambda Layers isn’t the optimal solution for sharing code between Lambda functions.
Within a single project or service, the straightforward approach is to modularize the shared code and reference them directly.
Most popular deployment tools, including the Serverless Framework, SAM, and CDK, support this.
Unfortunately, this doesn’t work for Amplify users.
The Problem with Amplify
When using Amplify’s amplify add
command to create a function, the tool manages it and only bundles contents inside the function’s src
folder.
This strategy, while effective in minimizing bundle size and cold start duration, makes it hard to include local modules outside the src
directory.
Consequently, sharing code across functions within the same project becomes a challenge.
The official documentation [2] suggests publishing shared code into a Lambda layer, but this requires an additional deployment cycle every time you update shared code. Plus, local mocking of functions using a layer isn’t supported by amplify mock
.
An alternative could be publishing shared code as an NPM package. While this solves the mocking issue, the extra deployment cycle remains.
Another potential solution is using symlinks or installing shared modules as local packages. In a monorepo setup, this works wonders for the purpose of sharing code [3].
However, it falls short with Amplify. The bundling process in Amplify doesn’t replace symlinks with actual content, leading to runtime errors.
So, what’s the solution?
A Workaround for Amplify Users
You can harness a little-known Amplify feature [4] that allows you to execute a custom script post npm install
in the function’s src
directory. Using this, you can replace symlinks with their referenced content. Here’s a step-by-step guide:
1. Setting up shared modules: Consider a function named getItems
and a local package called lib-utils
containing shared modules.
Use an index.js
as the main module for easy access:
module.exports = {
helpers: require('./helpers'),
utils: require('./utils')
}
2. Installing shared modules: In the getItems
function’s src
directory, run npm install ../../../lib
to bring in the shared modules.
This adds a symlink called lib-utils
in the node_modules
folder, pointing to the lib
folder where our shared modules reside.
3. Using shared modules: The shared modules can be imported in the getItems
function like this:
const { utils } = require('lib-utils')
module.exports.handler = async (event) => {
...
const x = utils.doSomething()
...
}
4. Custom scripting: Add a package.json
at the project root and define a script, amplify:getItems
, which effectively replaces the symlink with the actual content.
{
"scripts": {
"amplify:getItems": "cd amplify/backend/function/getItems/src/node_modules && cp -RL lib-utils lib-utils-temp && rm -rf lib-utils && mv lib-utils-temp lib-utils"
}
}
For every new function added, simply repeat steps 2–4.
Closing Thoughts
This is the most efficient workaround I’ve discovered. Ideally, the Amplify team will introduce a more seamless way to share code between functions. Simply replacing symlinks during bundling would be a huge step in the right direction.
If you have insights or alternative solutions for sharing code in Amplify, I’d love to hear from you. Lastly, a big shout-out to Ville Raukola for sparking this discussion during the Production-Ready Serverless workshop [5]. It’s an intensive course that can transform a novice into a serverless expert in just four weeks!
Links
[1] Lambda layer: not a package manager, but a deployment optimization
[2] Reuse code & assets using layers
[3] AWS Lambda: how to share code between functions in a monorepo
[5] Production-Ready Serverless workshop
Whenever you’re ready, here are 3 ways I can help you:
- Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
- I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
- Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.