Skip to main content

Project Structure

Understanding how Serverless Monolith discovers and organizes your modules.

your-project/
├── src/
│ └── modules/ # Modules directory (configurable)
│ ├── user/ # Module: user
│ │ ├── functions.yml # Function definitions
│ │ └── handlers/ # Handler implementations
│ │ ├── create/
│ │ │ └── index.ts
│ │ └── list/
│ │ └── index.ts
│ ├── order/ # Module: order
│ │ ├── functions.yml
│ │ └── handlers/
│ │ └── ...
│ └── notification/ # Module: notification
│ ├── functions.yml
│ └── handlers/
│ └── ...
├── monolith.config.ts # Configuration file
├── package.json
└── tsconfig.json

Module Discovery

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

Discovery Configuration

// monolith.config.ts
export default {
discovery: {
modulesDir: 'src/modules', // Where to look for modules
functionsFile: 'functions.yml', // Name of function definition file
strategy: 'explicit', // Discovery strategy
},
};

Discovery Strategies

StrategyDescription
explicitOnly discover modules with functions.yml
recursiveRecursively search for functions.yml in subdirectories

Functions File Format

The functions.yml file defines your serverless functions:

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

# SQS Function
processOrder:
handler: handlers/process/index.handler
events:
- sqs:
arn:
Fn::GetAtt: [ProcessOrderQueue, Arn]
batchSize: 10

Handler Structure

Each handler is a TypeScript/JavaScript file exporting a function:

// handlers/create/index.ts
import { APIGatewayProxyHandler } from 'aws-lambda';

export const handler: APIGatewayProxyHandler = async (event, context) => {
// Your logic here
return {
statusCode: 200,
body: JSON.stringify({ success: true }),
};
};

Environment Variables

Create a .env file in your project root:

# .env
DATABASE_URL=postgresql://localhost:5432/mydb
AWS_REGION=us-east-1
LOG_LEVEL=debug

Serverless Monolith automatically loads these variables before executing handlers.

TypeScript Configuration

Recommended tsconfig.json:

{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"]
}

Multiple Projects

For monorepo setups with multiple serverless projects, use the Proxy package:

monorepo/
├── services/
│ ├── api-users/
│ │ └── src/modules/...
│ ├── api-orders/
│ │ └── src/modules/...
│ └── api-payments/
│ └── src/modules/...
├── proxy.config.ts
└── lighthouse.config.ts

See the Proxy documentation for multi-service routing.