But first why should you learn this?
1. Because you can use claude 4 to build them with ease. If you need something done in n8n but can't figure it out or there isn't a node for it, just build a lambda function.
2. Takes n8n/relevance etc to next level because your agents can invoke these python functions.
With Python you have the ability to do SO much more but it's really not available in n8n.
3. Most importantly, Lambda functions are serverless meaning you only pay for them when they are running which is often for milliseconds so the cost is insanely cheap vs having a server running all the time for one thing.
Most API's are using Lambda functions and charging you a premium. But you can build your own and cut cost.
This particular guide will share how you can create AWS images using Lambda and then Auto store them in a public s3 bucket for you to share/download.
But the point is you can create all types of functions using Claude 4 once you see how easy it is.
Alright lets go.
Complete AWS Lambda Setup Guide - OpenAI Image Generator
From Brand New AWS Account to Working Function
PART 1: INITIAL AWS ACCOUNT SETUP
Step 1: Access AWS Console
Go to
aws.amazon.com/
Click "Sign in to the Console"
Enter your credentials and sign in
Make sure you're in the correct region (top-right corner)Recommended: us-east-1 (N. Virginia) or us-west-2 (Oregon)
PART 2: CREATE S3 BUCKET
Step 2: Create S3 Bucket for Images
In AWS Console search bar, type "S3"
Click on "S3" service
Click "Create bucket" (big orange button)
Configure Basic Settings:
Bucket name: openai-images-bucket-[your-name-or-number]Example: openai-images-bucket-john123
Must be globally unique, so add something personal
AWS Region: Choose same region as you selected earlier
Leave other settings as default for now
Configure Public Access:Scroll down to "Block Public Access settings for this bucket"
UNCHECK "Block all public access" ❌
Check the acknowledgment box that says "I acknowledge that the current settings..."
Scroll to bottom and click "Create bucket"
Step 3: Configure Bucket for Public Image Access
Click on your newly created bucket name (not the checkbox, the actual name)
Click the "Permissions" tab
Scroll down to "Bucket policy"
Click "Edit"
Copy and paste this policy (replace YOUR-BUCKET-NAME with your actual bucket name):
json{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
Click "Save changes"
✅ CHECKPOINT: Your S3 bucket is now ready to store public images.
PART 3: CREATE IAM ROLE
Step 4: Create IAM Role for Lambda
In AWS Console search bar, type "IAM"
Click on "IAM" service
In left sidebar, click "Roles"
Click "Create role" (blue button)
Select Trusted Entity:Select "AWS service" (should be selected by default)
Use case: Select "Lambda"
Click "Next"
Add Permissions - First Policy:In search box, type: AWSLambdaBasicExecutionRole
Check the checkbox next to it
Click "Next"
Name and Create Role:Role name: OpenAI-Image-Lambda-Role
Description: Role for OpenAI image generation Lambda function
Click "Create role"
Step 5: Add S3 Permissions to Role
Click on the role name OpenAI-Image-Lambda-Role you just created
Click "Add permissions" dropdown → "Create inline policy"
Click "JSON" tab
Delete the existing JSON and paste this (replace YOUR-BUCKET-NAME):
json{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
Click "Next"
Policy name: S3-Upload-Policy
Click "Create policy"
✅ CHECKPOINT: Your IAM role now has permissions to run Lambda and upload to S3.
PART 4: CREATE LAMBDA FUNCTION
Step 6: Create Lambda Function
In AWS Console search bar, type "Lambda"
Click on "Lambda" service
Click "Create function" (orange button)
Configure Function:Select "Author from scratch" (should be selected)
Function name: openai-image-generator
Runtime: Select "Python 3.11" from dropdown
Architecture: Leave as x86_64
Change Execution Role:Expand "Change default execution role"
Select "Use an existing role"
Existing role: Select OpenAI-Image-Lambda-Role from dropdown
Click "Create function"
Step 7: Configure Lambda Settings
Wait for function to be created (you'll see a green success banner)
Click on "Configuration" tab
In left sidebar, click "General configuration"
Click "Edit"
Update settings:Timeout: Change to 1 min 30 sec (or type 90 seconds)
Memory: Change to 512 MB
Click "Save"
Step 8: Add Environment Variables
Still in Configuration tab, click "Environment variables" in left sidebar
Click "Edit"
Click "Add environment variable"
First Variable:
Key: OPENAI_API_KEY
Value: your-actual-openai-api-key-here
Get this from
platform.openai.com/api-keys
Click "Add environment variable" again
Second Variable:
Key: S3_BUCKET_NAME
Value: your-actual-bucket-name-here (the name you created in Step 2)
Click "Save"
✅ CHECKPOINT: Your Lambda function is configured with proper timeout, memory, and environment variables.
PART 5: DEPLOY THE CODE
Step 9: Add the Python Code
Click on "Code" tab
You'll see lambda_function.py in the file explorer on the left
Click on lambda_function.py
Select ALL the default code (Ctrl A or Cmd A)
Delete it
Copy and paste your working code (the code from your document)
=== ACTUAL CODE ===
import json
import boto3
import urllib.request
import urllib.parse
import urllib.error
import base64
import uuid
import os
from typing import Dict, Any, List
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""
AWS Lambda function to generate images using OpenAI's gpt-image-1 API
and upload them to S3.
Expected event structure:
{
"prompt": "A description of the image to generate",
"size": "1024x1024" (optional, defaults to "auto"),
"n": 1 (optional, number of images to generate),
"background": "auto" (optional: "auto", "transparent", "opaque"),
"quality": "auto" (optional: "auto", "high", "medium", "low"),
"output_format": "png" (optional: "png", "jpeg", "webp"),
"output_compression": 100 (optional, 0-100),
"moderation": "auto" (optional: "auto", "low")
}
"""
try:
# Parse input parameters
body = event.get('body')
if isinstance(body, str):
body = json.loads(body)
elif body is None:
body = event
prompt = body.get('prompt')
if not prompt:
return {
'statusCode': 400,
'body': json.dumps({'error': 'prompt is required'})
}
# Extract optional parameters with defaults
size = body.get('size', 'auto')
n = body.get('n', 1)
background = body.get('background', 'auto')
quality = body.get('quality', 'auto')
output_format = body.get('output_format', 'png')
output_compression = body.get('output_compression', 100)
moderation = body.get('moderation', 'auto')
# Validate parameters
if n < 1 or n > 10:
return {
'statusCode': 400,
'body': json.dumps({'error': 'n must be between 1 and 10'})
}
# Environment variables
openai_api_key = os.environ.get('OPENAI_API_KEY')
s3_bucket = os.environ.get('S3_BUCKET_NAME')
if not openai_api_key:
return {
'statusCode': 500,
'body': json.dumps({'error': 'OPENAI_API_KEY environment variable not set'})
}
if not s3_bucket:
return {
'statusCode': 500,
'body': json.dumps({'error': 'S3_BUCKET_NAME environment variable not set'})
}
# Generate images using OpenAI API
image_urls = generate_images(
api_key=openai_api_key,
prompt=prompt,
size=size,
n=n,
background=background,
quality=quality,
output_format=output_format,
output_compression=output_compression,
moderation=moderation
)
# Upload images to S3 and get URLs
s3_urls = upload_images_to_s3(image_urls, s3_bucket, output_format)
return {
'statusCode': 200,
'body': json.dumps({
'success': True,
'images': s3_urls,
'count': len(s3_urls)
})
}
except Exception as e:
print(f"Error: {str(e)}")
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)})
}
def generate_images(api_key: str, prompt: str, size: str, n: int,
background: str, quality: str, output_format: str,
output_compression: int, moderation: str) -> List[str]:
"""
Generate images using OpenAI's gpt-image-1 API.
Returns:
List of base64-encoded image strings
"""
url = "
api.openai.com/v1/images/gen…"
payload = {
"model": "gpt-image-1",
"prompt": prompt,
"n": n,
"size": size,
"background": background,
"quality": quality,
"output_format": output_format,
"output_compression": output_compression,
"moderation": moderation
}
# Remove None values
payload = {k: v for k, v in payload.items() if v is not None}
# Convert payload to JSON
data = json.dumps(payload).encode('utf-8')
# Create request
req = urllib.request.Request(
url,
data=data,
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
)
try:
with urllib.request.urlopen(req, timeout=60) as response:
if response.status != 200:
error_data =
response.read().decode('utf-8')
raise Exception(f"OpenAI API error: {response.status} - {error_data}")
result = json.loads(
response.read().decode('utf-8'))
except urllib.error.HTTPError as e:
error_data =
e.read().decode('utf-8')
raise Exception(f"OpenAI API error: {e.code} - {error_data}")
except urllib.error.URLError as e:
raise Exception(f"Network error: {e.reason}")
# Extract base64 images from response
images = []
for image_data in result.get('data', []):
if 'b64_json' in image_data:
images.append(image_data['b64_json'])
else:
raise Exception("Expected base64 image data not found in response")
return images
def upload_images_to_s3(base64_images: List[str], bucket_name: str,
output_format: str) -> List[str]:
"""
Upload base64-encoded images to S3 and return public URLs.
Args:
base64_images: List of base64-encoded image strings
bucket_name: S3 bucket name
output_format: Image format (png, jpeg, webp)
Returns:
List of S3 URLs
"""
s3_client = boto3.client('s3')
s3_urls = []
# Determine file extension and content type
if output_format == 'jpeg':
extension = 'jpg'
content_type = 'image/jpeg'
elif output_format == 'webp':
extension = 'webp'
content_type = 'image/webp'
else: # png
extension = 'png'
content_type = 'image/png'
for i, base64_image in enumerate(base64_images):
try:
# Decode base64 image
image_data = base64.b64decode(base64_image)
# Generate unique filename
filename = f"generated-images/{uuid.uuid4()}.{extension}"
# Upload to S3
s3_client.put_object(
Bucket=bucket_name,
Key=filename,
Body=image_data,
ContentType=content_type,
CacheControl='max-age=31536000' # Cache for 1 year
)
# Generate public URL
s3_url = f"https://{bucket_name}.s3.amazonaws.com/{filename}"
s3_urls.append(s3_url)
except Exception as e:
print(f"Error uploading image {i}: {str(e)}")
raise Exception(f"Failed to upload image {i} to S3: {str(e)}")
return s3_urls
# Optional: Helper function for testing locally
def test_locally():
"""
Test function for local development.
Set environment variables before running.
"""
test_event = {
"prompt": "A serene mountain landscape with a lake at sunset",
"size": "1024x1024",
"n": 1,
"quality": "high",
"output_format": "png"
}
result = lambda_handler(test_event, None)
print(json.dumps(result, indent=2))
if __name__ == "__main__":
test_locally()
=== END OF CODE ===
Click "Deploy" (orange button)
Wait for "Successfully updated the function" message
✅ CHECKPOINT: Your code is now deployed to Lambda.
PART 6: TEST THE FUNCTION
Step 10: Create and Run Test
Still in Code tab, click "Test" (next to Deploy button)
Configure test event:Select "Create new event"
Event name: basic-test
Template: Leave as "hello-world"
Replace the JSON with this test case:
json{
"prompt": "A serene mountain landscape with a crystal clear lake reflecting the sky",
"size": "1024x1024",
"n": 1
}
Click "Save"
Click "Test" (this will run your function)
Step 11: Check Test Results
If Successful, you'll see:
Green banner saying "Execution result: succeeded"
Response should look like:
json{
"statusCode": 200,
"body": {
"success": true,
"images": [
"
your-bucket-name.s3.amazonaw…"
],
"count": 1
}
}
Click on the S3 URL to verify the image was generated correctly
If you get errors, see troubleshooting section below.
✅ CHECKPOINT: Your function successfully generates images and uploads them to S3!
PART 7: OPTIONAL - CREATE API GATEWAY
Step 12: Create API Gateway (Optional - for HTTP access)
In AWS Console search bar, type "API Gateway"
Click on "API Gateway" service
Under "REST API", click "Build" (not the Private one)
Configure API:Choose the protocol: REST
Create new API: Selected
API name: OpenAI-Image-API
Description: API for generating images with OpenAI
Endpoint Type: Regional
Click "Create API"
Step 13: Create API Resource and Method
In API Gateway console, click "Actions" dropdown
Select "Create Resource"
Configure Resource:Resource Name: generate-image
Resource Path: /generate-image (auto-filled)
Enable API Gateway CORS: ✅ Check this
Click "Create Resource"
With /generate-image selected, click "Actions" → "Create Method"
Select "POST" from dropdown → Click checkmark
Setup Method:Integration type: Lambda Function
Use Lambda Proxy integration: ✅ Check this
Lambda Region: Your region
Lambda Function: Start typing openai and select your function
Click "Save"
Click "OK" on the permission popup
Step 14: Deploy API
Click "Actions" → "Deploy API"
Deployment stage: Select "[New Stage]"
Stage name: prod
Click "Deploy"
Copy the Invoke URL (you'll need this for HTTP requests)
✅ CHECKPOINT: You now have an HTTP API endpoint for your image generator!
PART 8: VERIFICATION AND TESTING
Step 15: Test Different Scenarios
Test 1 - Basic Test (in Lambda console):
json{
"prompt": "A red apple on a white background"
}
Test 2 - Multiple Images:
json{
"prompt": "A futuristic city skyline",
"size": "1536x1024",
"n": 3,
"quality": "high"
}
Test 3 - API Gateway Test (using curl or Postman):
bashcurl -X POST
your-api-id.execute-api.regi… \
-H "Content-Type: application/json" \
-d '{
"prompt": "A magical forest with glowing mushrooms",
"size": "1024x1024",
"n": 1
}'
Step 16: Verify S3 Images
Go to S3 console
Click on your bucket
You should see a generated-images/ folder
Click on it to see your generated images
Click on any image file to view/download it
TROUBLESHOOTING COMMON ISSUES
Error: "OPENAI_API_KEY environment variable not set"
Solution: Go back to Step 8 and double-check your environment variables.
Error: "S3_BUCKET_NAME environment variable not set"
Solution: Verify the bucket name in environment variables matches exactly.
Error: "Access Denied" when uploading to S3
Solution:
Check IAM role has the S3 policy (Step 5)
Verify bucket name in IAM policy matches your actual bucket name
Error: OpenAI API errors
Solution:
Verify your OpenAI API key is valid
Check you have credits/quota on your OpenAI account
Ensure your API key has access to gpt-image-1 model
Error: "Task timed out after X seconds"
Solution:
Increase Lambda timeout (Step 7)
Try with smaller images or fewer images (n=1)
Images not accessible via URL
Solution:
Check bucket policy is set correctly (Step 3)
Verify bucket has public read access enabled
FINAL CHECKLIST
S3 bucket created with public read access
IAM role created with Lambda and S3 permissions
Lambda function created with correct runtime and role
Environment variables set (OPENAI_API_KEY, S3_BUCKET_NAME)
Lambda timeout set to 90 seconds
Lambda memory set to 512 MB
Code deployed successfully
Function tested with sample prompt
Images generated and accessible via S3 URLs
API Gateway created (optional)
API tested via HTTP request (if using API Gateway)
🎉 CONGRATULATIONS! Your OpenAI image generation Lambda function is now fully operational!
WHAT YOU'VE BUILT
You now have:
✅ Lambda function that generates images using OpenAI's gpt-image-1 API
✅ S3 storage for generated images with public access
✅ Proper security with IAM roles and policies
✅ HTTP API (optional) for external access
✅ Error handling and logging via CloudWatch
Your function accepts prompts and returns public S3 URLs to generated images!
Now to use your new function in n8n you can search for the Lambda node in n8n and then connect your AWS connect which will allow you to select the functions you created.
Then just select invoke as the operation and then send the data the function needs to run in the json input area.
But if you get stuck Claude 4 can help you solve this as well.
For example for this function and step by step guide I used this simple prompt:
"i want to create a python lambda function that calls the openai gpt-image-1 api to generate an image. Here are the details of the api call:
We only want to call the gpt-image-1. The prompt and size will be sent to you. Once you get back the base64 from the openai call we need to convert the base64/upload it to a s3 bucket so we can view the image and return the s3 link(s)."
Claude did the rest. I just clicked a few buttons and had a running function.
Anyway, that's it. Have fun and take your building to the next level.