Hit a 30s Timeout? Here’s How Lambda Function URLs Save the Day
“API Gateway times out after 30 seconds — even if your Lambda is still running.”
If you’ve ever hit that wall while building an API in AWS, you’re not alone.
But in 2022, AWS quietly released a feature that changes the game — Lambda Function URLs.
They give your function a direct HTTPS endpoint — with no API Gateway, no 30-second timeout, and no extra setup.
In this article, we’ll see why this matters, explore when to use Function URLs over API Gateway, and build a working example — deployed directly via AWS SAM.
The Problem: API Gateway’s 30-Second Timeout
When you expose a Lambda function through API Gateway, you inherit its timeout limit: Maximum: 29–30 seconds.
Even if your Lambda needs a few seconds more — API Gateway disconnects.
Your function still runs in the background, but the client gets a 504 Gateway Timeout.
This is painful when:
- You’re generating long reports or PDFs
- Doing ML inference or ETL workloads
- Running large database queries
- Doing batch job triggers that take >30s
You can’t easily stream intermediate results or extend the timeout — API Gateway simply caps it.
The Fix: Lambda Function URLs
Lambda Function URLs remove that cap.
They connect directly to your Lambda with:
- No API Gateway in between
- Full 15-minute timeout window (the Lambda max)
- HTTPS endpoint automatically created
- Built-in IAM or public access
- Optional CORS configuration
Basically — fewer moving parts, fewer bills, and a lot more freedom.
You can invoke it via any HTTP client — browser, curl, Python, Postman — and it’ll stay alive as long as your Lambda runs (up to 15 minutes).
Behind the Scenes — How Function URLs Work
Under the hood, Function URLs use the Lambda HTTPS front-end service, the same infrastructure AWS uses internally when you invoke Lambda via the AWS Console or SDKs.
When you create a Function URL:
- AWS provisions a secure HTTPS endpoint bound to that function’s ARN.
- Every request is signed and routed directly to the Lambda service, skipping API Gateway’s routing layer.
- The connection remains open until Lambda completes or times out (15 min).
This direct invocation path reduces latency, simplifies architecture, and eliminates the 30-second choke point entirely.
In performance tests, cold starts are identical to regular Lambda invocations. For compute-heavy workloads, skipping API Gateway can save 50–100 ms of overhead per request.
When should you use and when not to use Lambda Function URLs?
Ideal Scenarios
— Long-running compute (reports, ML inference, data transformation)- No 30s timeout
— Quick proof-of-concepts
— Event processing / asynchronous triggers
Not Ideal For
— Complex routing or versioning
— Multi-endpoint APIs
— Public APIs needing detailed access control
Building a Simple POC — Deploying via AWS SAM
Let’s create a small report-generation Lambda that simulates a long-running task (10 seconds), and deploy it directly with a Function URL.
- Project Structure
2. app.py
import os
import json
import logging
from openai import OpenAI
from typing import DictLOG = logging.getLogger()
LOG.setLevel(logging.INFO)OPENAI_API_KEY = ""
if not OPENAI_API_KEY:
LOG.warning("OPENAI_API_KEY not set - function will fail when calling OpenAI.")client = OpenAI(api_key=OPENAI_API_KEY)OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
def build_chat_prompt(question: str) -> Dict:
"""
Build the messages payload for the Chat Completions API.
"""
messages = [
{"role": "system", "content": "You are a helpful assistant that answers concisely."},
{"role": "user", "content": question}
]
return {"model": OPENAI_MODEL, "messages": messages, "max_tokens": 512, "temperature": 0.2}def call_openai_chat(payload: Dict) -> str:
"""
Call OpenAI Chat Completions API and return the assistant text.
"""
try:
# Use the new OpenAI API format
response = client.chat.completions.create(
model=payload["model"],
messages=payload["messages"],
max_tokens=payload["max_tokens"],
temperature=payload["temperature"]
)
# Extract the content from the new response format
if response.choices and len(response.choices) > 0:
return response.choices[0].message.content.strip()
else:
return "No response generated"
except Exception as e:
LOG.exception("OpenAI API call failed.")
raisedef lambda_handler(event, context):
"""
Expects event.body (when invoked via Function URL) to be either JSON string or dict:
{"question":"What is X?"}
"""
LOG.info("Event: %s", event) body = event.get("body") if isinstance(event, dict) else None
if isinstance(body, str):
try:
body = json.loads(body)
except json.JSONDecodeError:
body = {"question": body} if not body or "question" not in body:
return {
"statusCode": 400,
"body": json.dumps({"error": "Please send JSON with a 'question' field."}),
"headers": {"Content-Type": "application/json"}
} question = body["question"]
LOG.info("Received question: %s", question) # Prepare OpenAI payload and call
payload = build_chat_prompt(question)
try:
answer = call_openai_chat(payload)
except Exception as e:
return {
"statusCode": 502,
"body": json.dumps({"error": "OpenAI call failed", "detail": str(e)}),
"headers": {"Content-Type": "application/json"}
}
return {
"statusCode": 200,
"body": json.dumps({"question": question, "answer": answer}),
"headers": {"Content-Type": "application/json"}
}
3. template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda Function URL POC - Q/A with OpenAIGlobals:
Function:
Timeout: 900 # up to 15 minutes for long-running tasks
Runtime: python3.11
MemorySize: 512Resources:
QaFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: lambda-qa-gpt-poc
Handler: app.lambda_handler
CodeUri: .
Runtime: python3.11
Timeout: 900
MemorySize: 512
Environment:
Variables:
# set OPENAI_API_KEY during deployment (sam deploy --guided will prompt)
OPENAI_API_KEY: ""
OPENAI_MODEL: "gpt-4o-mini"
Policies:
- AWSLambdaBasicExecutionRole
FunctionUrlConfig:
AuthType: NONE
Cors:
AllowOrigins:
- "*"
AllowMethods:
- POST
4. requirements.txt
openai>=1.0.05. Deploy via SAM CLI
sam build
sam deploy --guidedDuring deploy, SAM will:
- Create the Lambda function
- Automatically provision a Function URL
- Print the URL at the end
FunctionUrl: https://abc123.lambda-url.us-east-1.on.aws/Press enter or click to view image in full size
once deployed you can check it in the console you will get the function url there or you can print it in the template itself.
Authentication Gotcha
- When
AuthType: NONE, anyone can hit the endpoint — including bots and crawlers. - Use
AuthType: AWS_IAMor implement custom auth logic in the function itself .
Custom Domains Support (As of 2025)
- You still can’t attach a custom domain directly to a Function URL.
- The workaround: use CloudFront → Function URL origin, and attach your SSL cert to CloudFront.
- This setup also adds caching and rate limiting — making it production-friendly.
Security & Best Practices
Even though Function URLs can be public, don’t leave them open unless you need to.
- Use
AuthType: AWS_IAMfor internal or authenticated access. - Add CORS properly if you expect browser clients.
- For public endpoints, protect them behind CloudFront + WAF to block abuse.
- Consider adding an API key or signed query param check inside Lambda.
- Monitor usage via CloudWatch Logs and Lambda metrics.
Also, set Timeouts and Memory thoughtfully — long-running doesn’t mean infinite!
If your task regularly exceeds 5–10 minutes, it might be better suited for Step Functions or Fargate.
Key Takeaways
- API Gateway = Feature-rich API management, but limited to 30s per request.
- Lambda Function URLs = Lightweight HTTPS endpoints with 15-minute limit and zero overhead.
- Perfect for long-running, compute-heavy, or internal API use cases.
- Can be deployed instantly with AWS SAM — no extra services needed.
Think of Function URLs as “serverless endpoints without the ceremony.”
They don’t replace API Gateway — but for certain workloads, they absolutely outperform it.
Conclusion
Function URLs are not just a simpler API entrypoint — they’re a cost-effective, timeout-free, direct compute surface for specific workloads.
Use them when you need long-running tasks, simplicity, or private internal tools — but wrap them carefully if you expect scale or public traffic.
About the Author
Ankur Singh started his journey as a Software Engineer at CodeStax.Ai. He loves to explore multiple domains and loves to solve problems in an efficient manner.
You could also refer the below link written by the author
How to Launch and Auto-Scale Web Apps with AWS App Runner — No EC2 or DevOps Needed
About CodeStax.Ai
At CodeStax.Ai, we stand at the nexus of innovation and enterprise solutions, offering technology partnerships that empower businesses to drive efficiency, innovation, and growth, harnessing the transformative power of no-code platforms and advanced AI integrations.
But the real magic? It’s our tech tribe behind the scenes. If you’ve got a knack for innovation and a passion for redefining the norm, we’ve got the perfect tech playground for you. CodeStax.Ai offers more than a job — it’s a journey into the very heart of what’s next. Join us, and be part of the revolution that’s redefining the enterprise tech landscape
