Cannot Exclude parent node_modules directory

I’m using the Serverless Framework to deploy an API Gateway and AWS Lambda functions together.

Yesterday, I successfully deployed 6 Lambda functions using a single serverless.yaml file located in the parent directory of the individual Lambda npm projects. Each function’s package size was between 500 KB and 5 MB, depending on the function.

However, when I tried deploying the same setup today, I noticed that all the functions now include the node_modules directory from the parent directory, even though the functions don’t use it. This has significantly increased the package size for each Lambda function.

The directories and the serverless.yaml file haven’t changed since yesterday, so I’m unsure why this is happening. How can I exclude the node_modules directory from the parent directory during deployment?

Here’s the serverless.yaml file I’m using (located at project-lambdas/serverless.yaml).

service: projects

frameworkVersion: '4'

provider:
  name: aws
  runtime: nodejs20.x
  region: ap-northeast-2 # seoul
  role: ${self:custom.ENV.ARN.lambdaRole}
  stage: ${opt:stage, 'dev'}
  vpc:
    securityGroupIds: ${self:custom.ENV.VPC.securityGroupIds}
    subnetIds: ${self:custom.ENV.VPC.subnetIds}

package:
  individually: true
  excludeDevDependencies: true

functions:
  user-auth:
    handler: api-user-auth-ts/src/lambda.handler
    memorySize: 512
    timeout: 15
    package:
      include:
        - api-user-auth-ts/**
      exclude:
        - ../node_modules/**
    events:
      - http:
          path: /
          method: get
      - http:
          path: api/user-auth
          method: get
      - http:
          path: api/user-auth/{proxy+}
          method: any

  community:
    handler: api-community-ts/src/lambda.handler
    memorySize: 512
    timeout: 15
    package:
      include:
        - api-community-ts/**
      exclude:
        - ../node_modules/**
    events:
      - http:
          path: api/community
          method: get
      - http:
          path: api/community/{proxy+}
          method: any

  id-generator:
    handler: lambdas/id-generator/src/lambda.handler
    memorySize: 256
    package:
      include:
        - lambdas/id-generator/**
      exclude:
        - ../node_modules/**

  ncp-mailer:
    handler: lambdas/ncp-mailer/src/lambda.handler
    memorySize: 256
    package:
      include:
        - lambdas/ncp-mailer/**
      exclude:
        - ../node_modules/**

  s3-manager:
    role: ${self:custom.ENV_LAMBDAS.ARN.lambdaRoleS3}
    handler: lambdas/s3-manager/src/lambda.handler
    memorySize: 256
    package:
      include:
        - lambdas/s3-manager/**
      exclude:
        - ../node_modules/**
  token-manager:
    handler: lambdas/token-manager/src/lambda.handler
    memorySize: 256
    package:
      include:
        - lambdas/token-manager/**
      exclude:
        - ../node_modules/**

build:
  esbuild:
    bundle: true
    minify: true
    exclude:
      - 'projects-lambdas/node_modules/**'

# Custom Variables
custom:
  stages:
    - dev
    - qa
    - release
  ENV: ${file(./env.${self:provider.stage}.js):ENV_CONFIG}
  ENV_AUTH: ${file(./api-user-auth-ts/env.${self:provider.stage}.js):ENV_CONFIG}
  ENV_COMMUNITY: ${file(./api-community-ts/env.${self:provider.stage}.js):ENV_CONFIG}
  ENV_LAMBDAS: ${file(./lambdas/env.${self:provider.stage}.js):ENV_CONFIG}

To explain directories
project-lambdas/(npm project to use AWS-SDK when load env.js file)
└ serverless.yaml
└ node_modules/ ← which is include all other function package
└ api-user-auth-ts/(npm project)
    └ node_modules/
└ api-community-ts/(npm project)
    └ node_modules/
└ lambdas
    └ id-generator/(npm project)
       └ node_modules/
    └ ncp-mailer/(npm project)
       └ node_modules/
    └ s3-manager/(npm project)
       └ node_modules/
    └ token-manager/(npm project)
       └ node_modules/

the only one way to avoid is “exclude everything in the parent/node_modules” at the moment…

build:
  esbuild:
    bundle: true
    minify: true
    exclude:
      - 'aws-sdk'
      - '@aws-crypto'
      - 'balanced-match'
      - 'degenerator'
      - 'for-each'
      - 'immediate'
      - 'jszip'
      - 'pako'
      - 'shebang-command'
      - 'universalify'
      - '@aws-sdk'
      - 'base64-js'
      - 'delayed-stream'
      - 'foreground-child'
      - 'inherits'
      - 'lie'
      - 'param-case'
      - 'shebang-regex'
      - 'update-browserslist-db'
      - '@esbuild'
      - 'basic-ftp'
      - 'desm'
      - 'form-data'
      - 'ip-address'
      - 'loader-runner'
      - 'parse5'
      - 'signal-exit'
      - 'uri-js'
      - '@hapi'
      - 'bowser'
      - 'dot-case'
      - 'formdata-polyfill'
      - 'is-arguments'
      - 'long-timeout'
      - 'pascal-case'
      - 'smart-buffer'
      - 'url'
      - '@isaacs'
      - 'boxen'
      - 'eastasianwidth'
      - 'fs-extra'
      - 'is-callable'
      - 'lower-case'
      - 'path-key'
      - 'socks'
      - 'util'
      - '@jridgewell'
      - 'brace-expansion'
      - 'electron-to-chromium'
      - 'fsevents'
      - 'is-docker'
      - 'lru-cache'
      - 'path-scurry'
      - 'socks-proxy-agent'
      - 'util-deprecate'
      - '@jsep-plugin'
      - 'browserslist'
      - 'emoji-regex'
      - 'function-bind'
      - 'is-fullwidth-code-point'
      - 'luxon'
      - 'picocolors'
      - 'sorted-array-functions'
      - 'uuid'
      - '@pkgjs'
      - 'buffer'
      - 'enhanced-resolve'
      - 'get-intrinsic'
      - 'is-generator-function'
      - 'merge-stream'
      - 'possible-typed-array-names'
      - 'source-map'
      - 'velocityjs'
      - '@smithy'
      - 'buffer-from'
      - 'entities'
      - 'get-stream'
      - 'is-inside-container'
      - 'mime-db'
      - 'process-nextick-args'
      - 'source-map-support'
      - 'watchpack'
      - '@tootallnate'
      - 'call-bind'
      - 'es-define-property'
      - 'get-tsconfig'
      - 'is-stream'
      - 'mime-types'
      - 'proxy-agent'
      - 'sprintf-js'
      - 'web-streams-polyfill'
      - '@types'
      - 'camel-case'
      - 'es-errors'
      - 'get-uri'
      - 'is-typed-array'
      - 'mimic-fn'
      - 'proxy-from-env'
      - 'string-width'
      - 'webpack'
      - '@webassemblyjs'
      - 'camelcase'
      - 'es-module-lexer'
      - 'glob'
      - 'is-wsl'
      - 'minimatch'
      - 'punycode'
      - 'string-width-cjs'
      - 'webpack-sources'
      - '@xtuc'
      - 'caniuse-lite'
      - 'esbuild'
      - 'glob-to-regexp'
      - 'isarray'
      - 'minipass'
      - 'querystring'
      - 'string_decoder'
      - 'which'
      - 'acorn'
      - 'chalk'
      - 'escalade'
      - 'gopd'
      - 'isexe'
      - 'ms'
      - 'randombytes'
      - 'strip-ansi'
      - 'which-typed-array'
      - 'agent-base'
      - 'chrome-trace-event'
      - 'escodegen'
      - 'graceful-fs'
      - 'jackspeak'
      - 'neo-async'
      - 'readable-stream'
      - 'strip-ansi-cjs'
      - 'widest-line'
      - 'ajv'
      - 'clean-css'
      - 'eslint-scope'
      - 'has-flag'
      - 'java-invoke-local'
      - 'netmask'
      - 'relateurl'
      - 'strip-final-newline'
      - 'wrap-ansi'
      - 'ajv-keywords'
      - 'cli-boxes'
      - 'esprima'
      - 'has-property-descriptors'
      - 'jest-worker'
      - 'no-case'
      - 'resolve-pkg-maps'
      - 'strnum'
      - 'wrap-ansi-cjs'
      - 'ansi-align'
      - 'color-convert'
      - 'esrecurse'
      - 'has-proto'
      - 'jmespath'
      - 'node-domexception'
      - 'rimraf'
      - 'supports-color'
      - 'ws'
      - 'ansi-regex'
      - 'color-name'
      - 'estraverse'
      - 'has-symbols'
      - 'jose'
      - 'node-fetch'
      - 'safe-buffer'
      - 'tapable'
      - 'xml2js'
      - 'ansi-styles'
      - 'combined-stream'
      - 'esutils'
      - 'has-tostringtag'
      - 'js-string-escape'
      - 'node-releases'
      - 'sax'
      - 'terser'
      - 'xmlbuilder'
      - 'array-unflat-js'
      - 'commander'
      - 'events'
      - 'hasown'
      - 'jsbn'
      - 'node-schedule'
      - 'schema-utils'
      - 'terser-webpack-plugin'
      - 'ast-types'
      - 'core-util-is'
      - 'execa'
      - 'html-loader'
      - 'jsep'
      - 'npm-run-path'
      - 'serialize-javascript'
      - 'tree-kill'
      - 'asynckit'
      - 'cron-parser'
      - 'fast-deep-equal'
      - 'html-minifier-terser'
      - 'json-parse-even-better-errors'
      - 'onetime'
      - 'serverless'
      - 'tslib'
      - 'available-typed-arrays'
      - 'cross-spawn'
      - 'fast-json-stable-stringify'
      - 'http-proxy-agent'
      - 'json-schema-traverse'
      - 'p-memoize'
      - 'serverless-domain-manager'
      - 'tsx'
      - 'aws-sdk'
      - 'data-uri-to-buffer'
      - 'fast-xml-parser'
      - 'https-proxy-agent'
      - 'jsonfile'
      - 'pac-proxy-agent'
      - 'serverless-offline'
      - 'tunnel'
      - 'axios'
      - 'debug'
      - 'fetch-blob'
      - 'human-signals'
      - 'jsonpath-plus'
      - 'pac-resolver'
      - 'set-function-length'
      - 'type-fest'
      - 'axios-proxy-builder'
      - 'define-data-property'
      - 'follow-redirects'
      - 'ieee754'
      - 'jsonschema'
      - 'package-json-from-dist'
      - 'setimmediate'
      - 'undici-types'

this one not works…

build:
  esbuild:
    bundle: true
    minify: true
    exclude:
      - node_modules/**
      - 'node_modules/**'

Every project has its own node_modules folder and package.json file. Node_modules contains all the external code your code depends on (dependencies). Package.json contains all the info about which code (dependencies) needs to be downloaded into node_modules.
9Apps Tutuapp