Package Exports
- modal-bridge-constructs
- modal-bridge-constructs/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (modal-bridge-constructs) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
modal-bridge-constructs
AWS CDK constructs for integrating Modal serverless GPU/CPU functions with AWS services.
Bridge the gap between AWS event sources (S3, SQS, API Gateway, etc.) and Modal's powerful serverless compute platform. Trigger Modal functions from AWS events with full IAM security via OIDC federation.
Features
- Event-driven Modal functions - Trigger Modal functions from any AWS Lambda event source
- Two integration patterns -
spawnfor fire-and-forget,remotefor synchronous responses - Secure OIDC authentication - Modal functions can assume AWS IAM roles without long-lived credentials
- CDK native - Familiar patterns like
grantReadWrite()work seamlessly - Automatic secret management - Modal API tokens stored securely in AWS Secrets Manager
Installation
npm install modal-bridge-constructsPrerequisites
- Modal account - Sign up at modal.com
- Modal API token - Generate at modal.com/settings
- A deployed Modal app - The Modal function you want to invoke must already be deployed
- AWS account
Quick Start
import { ModalFunction, ModalIntegration, ModalSecret } from 'modal-bridge-constructs';
import { Bucket, EventType } from 'aws-cdk-lib/aws-s3';
import { S3EventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
// Create an S3 bucket that will trigger the Modal function
const bucket = new Bucket(this, 'ImageBucket', {
bucketName: 'my-image-bucket',
});
// Create the Modal function bridge
const modalFunction = new ModalFunction(this, 'ImageProcessor', {
functionName: 'process_image', // Name of your Modal function
integrationPattern: ModalIntegration.Remote,
modalConfig: {
appName: 'my-modal-app', // Your Modal app name
workspaceId: 'ws-abc123', // Your Modal workspace ID
environment: 'main', // Modal environment
},
});
// Grant the Modal function access to the bucket via OIDC
bucket.grantReadWrite(modalFunction);
// Trigger on S3 uploads
modalFunction.addEventSource(
new S3EventSource(bucket, {
events: [EventType.OBJECT_CREATED],
filters: [{ prefix: 'uploads/', suffix: '.png' }],
})
);How It Works
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AWS Event │────▶│ Lambda │────▶│ Modal │────▶│ Your Modal │
│ (S3, SQS, │ │ Bridge │ │ API │ │ Function │
│ etc.) │ │ │ │ │ │ (GPU/CPU) │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Secrets │ │ AWS (S3, │
│ Manager │ │ etc.) via │
│ (Token) │ │ OIDC │
└─────────────┘ └─────────────┘- An AWS event (S3 upload, SQS message, etc.) triggers the Lambda bridge function
- The Lambda retrieves your Modal API token from Secrets Manager
- The Lambda invokes your Modal function via the Modal API
- Your Modal function can access AWS resources using OIDC-based IAM roles (no credentials needed)
API Reference
ModalFunction
The main construct that creates a Lambda bridge to invoke Modal functions.
new ModalFunction(scope, id, {
// Required
functionName: string; // Name of the Modal function to invoke
integrationPattern: ModalIntegration; // Spawn or Remote
modalConfig: ModalConfig; // Modal app configuration
// Optional
params?: Record<string, any>; // Static parameters passed to every invocation
delimiter?: string; // Delimiter for generated resource names
executionRole?: Role; // Custom Lambda execution role
lambdaRuntime?: Runtime; // Lambda runtime (default: Python 3.10)
lambdaTimeout?: Duration; // Lambda timeout (default: 5 minutes)
oidcProvider?: OpenIdConnectProvider; // Existing OIDC provider
});Methods:
| Method | Description |
|---|---|
addEventSource(source) |
Add an AWS event source (S3, SQS, SNS, etc.) |
ModalConfig
Configuration for connecting to your Modal app.
interface ModalConfig {
appName: string; // Your Modal app name
environment: string; // Modal environment (e.g., 'main', 'dev')
workspaceId: string; // Your Modal workspace ID
tokenSecret?: Secret; // Optional: existing secret with Modal token. One will be created if not provided.
}Finding your workspace ID:
- Go to modal.com/settings
- Your workspace ID is shown under "Workspace"
ModalIntegration
Choose how your Modal function is invoked:
| Pattern | Description | Use Case |
|---|---|---|
ModalIntegration.Spawn |
Fire-and-forget async invocation | Long-running tasks, background jobs |
ModalIntegration.Remote |
Synchronous invocation, waits for result | Quick processing, need return value |
ModalSecret
A helper construct for creating Secrets Manager secrets for Modal tokens.
const secret = new ModalSecret(this, 'MyModalSecret', {
secretName: 'my-modal-token', // Optional custom name
});After deployment, update the secret in AWS Console or CLI with your actual Modal credentials:
{
"MODAL_TOKEN_ID": "your-token-id",
"MODAL_TOKEN_SECRET": "your-token-secret"
}Integration Patterns
Spawn (Fire-and-Forget)
Use spawn when you don't need to wait for the result. The Lambda returns immediately with a function call ID.
const modalFunction = new ModalFunction(this, 'BackgroundProcessor', {
functionName: 'train_model',
integrationPattern: ModalIntegration.Spawn,
modalConfig: { ... },
});Lambda response:
{
"status": "Success",
"response": {
"function_call_id": "fc-abc123"
}
}Remote (Synchronous)
Use remote when you need the result of the Modal function. The Lambda waits for completion.
const modalFunction = new ModalFunction(this, 'ImageProcessor', {
functionName: 'process_image',
integrationPattern: ModalIntegration.Remote,
modalConfig: { ... },
});Lambda response:
{
"status": "Success",
"response": {
"result": { "processed": true, "output_path": "/mnt/output.png" }
}
}OIDC Authentication
Modal functions can securely access AWS resources without storing AWS credentials. The construct automatically:
- Creates an OIDC provider for
oidc.modal.com - Configures the Lambda execution role to be assumable by your specific Modal function
- Scopes access by workspace, environment, app, and function name
In your Modal function, use CloudBucketMount to access S3:
import modal
app = modal.App('my-modal-app')
@app.function(
volumes={
"/mnt": modal.CloudBucketMount(
bucket_name='my-image-bucket',
oidc_auth_role_arn='arn:aws:iam::123456789:role/ImageProcessor_remote_role'
)
}
)
def process_image(event: dict, params: dict):
# Access S3 files directly via /mnt
with open('/mnt/uploads/image.png', 'rb') as f:
# Process the image...
passEvent Sources
ModalFunction works with any Lambda event source. Common examples:
S3
import { S3EventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
modalFunction.addEventSource(
new S3EventSource(bucket, {
events: [EventType.OBJECT_CREATED],
})
);SQS
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
modalFunction.addEventSource(
new SqsEventSource(queue, {
batchSize: 10,
})
);API Gateway
import { LambdaIntegration } from 'aws-cdk-lib/aws-apigateway';
api.root.addMethod('POST', new LambdaIntegration(modalFunction.handler));Scheduled Events
import { Rule, Schedule } from 'aws-cdk-lib/aws-events';
import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets';
new Rule(this, 'ScheduleRule', {
schedule: Schedule.rate(Duration.hours(1)),
targets: [new LambdaFunction(modalFunction.handler)],
});Static Parameters
Pass static parameters that are included with every invocation:
const modalFunction = new ModalFunction(this, 'Processor', {
functionName: 'process',
integrationPattern: ModalIntegration.Remote,
modalConfig: { ... },
params: {
outputFormat: 'png',
quality: 95,
resize: { width: 1920, height: 1080 },
},
});Your Modal function receives these in the params argument:
@app.function()
def process(event: dict, params: dict):
output_format = params['outputFormat'] # 'png'
quality = params['quality'] # 95
# ...Contributing
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
License
Apache-2.0 - see LICENSE for details.