serverless-webpack is a Serverless Framework plugin that bundles your Lambda functions with Webpack so each deployed package contains only the code and dependencies a given handler actually needs, which shrinks cold starts and, as a side effect, trims your deployed attack surface. If you deploy Node.js or TypeScript functions with the Serverless Framework, serverless-webpack is one of the most common ways to avoid shipping your entire node_modules tree into every function.
This post explains what the plugin does, how the bundling helps and hurts security, and the practical steps to use it safely.
What serverless-webpack does
Without a bundler, the Serverless Framework tends to package your whole dependency tree with each function. That produces large artifacts, slower cold starts, and a lot of code you never call sitting in production. serverless-webpack runs Webpack over each handler, follows the actual import/require graph, and produces a compiled bundle per function containing only what that entry point reaches.
The plugin hooks into the standard lifecycle, so it works with serverless package, serverless deploy, and serverless deploy function, and supports local iteration through serverless invoke local, serverless invoke local --watch, and integration with serverless-offline to simulate API Gateway locally. Because it is Webpack under the hood, you also get tree-shaking, Babel or TypeScript transpilation, and custom loaders.
A minimal setup looks like this. Install the plugin and Webpack:
npm install --save-dev serverless-webpack webpack
Register it in serverless.yml:
plugins:
- serverless-webpack
custom:
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
packager: npm
A typical config targets Node and marks the AWS SDK as external because Lambda already provides it:
const path = require('path');
module.exports = {
target: 'node',
mode: 'production',
entry: slsw.lib.entries,
externals: ['aws-sdk'],
resolve: { extensions: ['.js', '.ts'] },
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js',
},
};
How bundling affects security, both ways
The security story with serverless-webpack has two sides, and it is worth being precise about each.
On the positive side, tree-shaking removes unreachable code. If a dependency exports ten modules and your handler uses one, the other nine do not ship. That is a genuine reduction in what runs in production, and it can mean a vulnerable code path in an unused corner of a library never makes it into the deployed function.
On the cautionary side, do not confuse a smaller bundle with a scanned bundle. Tree-shaking is a performance optimization, not a security control. It only eliminates code the bundler can prove is unreachable at build time; dynamic require calls, reflection, and anything the analyzer cannot statically resolve get pulled in anyway. And a vulnerability in code your handler actually uses is still in the bundle. The reduced footprint is a nice side effect, not a substitute for dependency scanning.
The dependency risks to watch
serverless-webpack sits on top of a substantial dependency graph: Webpack itself, its loaders and plugins, and whatever transpilers you add. This is build-time tooling, which people often treat as lower risk than runtime dependencies, but a compromised build plugin can inject code into every function you ship. That makes your devDependencies part of your production supply chain.
Three habits keep this in check. First, pin versions with a committed lockfile so a build machine cannot silently pull a newer, tampered release. Second, scan devDependencies, not just runtime ones — a malicious Webpack loader is a supply chain attack even though it never runs in Lambda. Third, keep the plugin and Webpack current, because bundler and loader ecosystems move fast and older majors accumulate advisories in their own transitive trees. An SCA scanner can surface those transitive issues across both dependency sets rather than only the packages you name directly.
The includeModules behavior
One configuration detail matters for both size and security: includeModules. When enabled, serverless-webpack detects which node modules could not be bundled (native modules, or anything marked external) and packages only those into the artifact, resolving them from your lockfile. This is what keeps the deployed package lean while still shipping the binaries that cannot be bundled.
The security-relevant point is that whatever includeModules pulls in is real production code with a real dependency tree. Native modules in particular deserve attention because they ship compiled binaries. Make sure those packages are in scope for your scanning, and be deliberate about the externals list — anything you mark external is a promise that the runtime, or the included modules, provides it safely.
Putting it together
serverless-webpack is a solid, actively used plugin, and smaller, tree-shaken Lambda packages are a real win for both performance and footprint. Just hold two ideas at once: the bundling reduces incidental exposure, and it does nothing to tell you whether the code that remains is vulnerable. Bundle for speed, scan for safety, and treat your build-time dependencies as part of the production supply chain. The Safeguard Academy has more on why devDependencies belong in your threat model.
FAQ
What does serverless-webpack do?
It is a Serverless Framework plugin that runs Webpack over each Lambda handler, producing a per-function bundle containing only the code and dependencies that handler reaches. The result is smaller deployment packages, faster cold starts, and support for TypeScript, Babel, and tree-shaking.
Does bundling with serverless-webpack make my Lambdas more secure?
Indirectly and partially. Tree-shaking removes provably unreachable code, which can drop a vulnerable but unused path from the artifact. It is not a security control, though — it will not remove vulnerabilities in code you actually call, and it cannot eliminate anything loaded dynamically. You still need dependency scanning.
Do I need to scan my devDependencies when using serverless-webpack?
Yes. Webpack, its loaders, and transpilers are build-time tooling, but a compromised build plugin can inject code into every function you deploy. Treat devDependencies as part of your production supply chain and include them in your scans.
What does the includeModules option do?
It tells the plugin to detect modules that could not be bundled — typically native modules or externals — and package only those into the artifact, resolving versions from your lockfile. It keeps deployments lean while still shipping binaries that Webpack cannot inline.