Skip to main content

Module Discovery

Learn how Serverless Monolith discovers and loads your modules.

How Discovery Works

Serverless Monolith automatically discovers modules based on the presence of a functions.yml file. Each directory containing this file is treated as a module.

src/modules/
├── user/ # Module: user
│ ├── functions.yml # ✓ Discovered
│ └── handlers/
├── order/ # Module: order
│ ├── functions.yml # ✓ Discovered
│ └── handlers/
└── shared/ # Not a module
└── utils.ts # ✗ No functions.yml

Discovery Strategies

Explicit Strategy (Default)

Only directories directly under modulesDir with functions.yml are discovered:

{
discovery: {
modulesDir: 'src/modules',
strategy: 'explicit'
}
}

Recursive Strategy

Searches recursively for functions.yml in subdirectories:

{
discovery: {
modulesDir: 'src',
strategy: 'recursive'
}
}

This allows nested module structures:

src/
├── domains/
│ ├── user/
│ │ └── functions.yml # ✓ Discovered
│ └── order/
│ └── functions.yml # ✓ Discovered
└── shared/
└── utils.ts # ✗ Ignored

Functions File Format

The functions.yml file defines your serverless functions:

# HTTP Functions
createUser:
handler: handlers/create/index.handler
events:
- http:
path: users
method: POST
cors: true

listUsers:
handler: handlers/list/index.handler
events:
- http:
path: users
method: GET
cors: true

getUserById:
handler: handlers/get/index.handler
events:
- http:
path: users/{id}
method: GET

# SQS Functions
processUserQueue:
handler: handlers/process/index.handler
events:
- sqs:
arn:
Fn::GetAtt: [ProcessUserQueue, Arn]
batchSize: 10

Handler Resolution

Handlers are resolved relative to the module directory:

src/modules/user/
├── functions.yml
└── handlers/
└── create/
└── index.ts # handler: handlers/create/index.handler

The handler path handlers/create/index.handler resolves to:

  • File: src/modules/user/handlers/create/index.ts
  • Export: handler

Path Parameters

Path parameters are defined using curly braces:

getUserById:
handler: handlers/get/index.handler
events:
- http:
path: users/{id}
method: GET

updateUserAddress:
handler: handlers/address/index.handler
events:
- http:
path: users/{userId}/addresses/{addressId}
method: PUT

These are available in the handler via event.pathParameters:

export const handler: APIGatewayProxyHandler = async (event) => {
const { id } = event.pathParameters || {};
// ...
};

Security Validations

The discovery system includes security validations:

  • Path Traversal Prevention: Handler paths cannot escape the module directory
  • File Existence Check: Warns if handler files don't exist
  • Export Validation: Validates that the specified export exists

Debugging Discovery

Enable discovery logging to debug issues:

{
logging: {
enabledCategories: ['moduleDiscovery'],
showRoutesTable: true
}
}

This will show:

[discovery] Scanning directory: src/modules
[discovery] Found module: user (3 functions)
[discovery] Found module: order (5 functions)
[discovery] Total: 2 modules, 8 functions

Next Steps