Build a fast, scalable, and production-grade Telegram Bot in 5 minutes using AWS Lambda, FastAPI, and the Serverless Framework — with full support for local development via uvicorn and ngrok.
- For pet projects, side projects, and production bots
- Manual server hosting
- Complicated scaling
- Maintenance headaches
This project solves that.
✅ SnapStart dramatically reduces Lambda cold start times..
✅ Horizontal scaling is automatic by AWS Lambda.
✅ Local development is effortless with uvicorn and ngrok.
✅ From a small side-project to millions of users — this architecture just works
✅ Parsed requests are fully typed with Pydantic v2, making your code cleaner and safer, just add business logic.
⚡ Features
- Blazing-fast response time (with AWS Lambda SnapStart)
- Fully serverless: no servers to manage
- Easily deployable in under 5 minutes
- Supports local FastAPI debug with uvicorn and ngrok
- Scales horizontally by design
- Fully typed with Pydantic v2
- Plug-and-play with Telegram Webhook API
🛠️ Technical Stack
- AWS Lambda – serverless compute
- API Gateway – to expose FastAPI as webhook endpoint
- FastAPI – async Python web framework
- Mangum – ASGI adapter for AWS Lambda
- httpx – async HTTP client to call Telegram API
- Serverless Framework – deploy & manage the stack
- Loguru – structured logging
- Pydantic v2 – data parsing & validation
- Docker - for collecting dependencies
| Package | Purpose |
|---|---|
pydantic>=2.0.0 | Type-safe Telegram request parsing |
fastapi | Web framework for both local and Lambda |
httpx | Asynchronous HTTP client for Telegram Bot API |
mangum | FastAPI to Lambda adapter |
loguru | Logging with nice formatting and context |
serverless | Infra deployment with AWS |
ngrok | Exposing local server to Telegram webhook |
src/ ├── app/ │ └── dispatcher.py # Business logic ├── models/ │ └── telegram_request.py # Typed Telegram webhook model ├── infrastructure/ │ └── telegram/ │ └── telegram_api.py # Wrapper around Telegram Bot API ├── entry_point_fastapi_app.py # FastAPI + Mangum Lambda entrypoint ├── settings.py # ENV-based config There is a single model for all Telegram requests, which is typed with Pydantic v2. It includes fields that Telegram can send, so you can easily access any data in your bot logic.
# part of src/models/telegram_request.py class Message(BaseModel): message_id: int from_: User = Field(..., alias="from") chat: Chat date: int text: Optional[str] = None entities: Optional[List[MessageEntity]] = None media_group_id: Optional[str] = None photo: Optional[List[Photo]] = None document: Optional[Document] = None class MyChatMember(BaseModel): chat: Chat from_: User = Field(..., alias="from") date: int old_chat_member: ChatMemberStatus new_chat_member: ChatMemberStatus class TelegramRequest(BaseModel): update_id: int message: Optional[Message] = None my_chat_member: Optional[MyChatMember] = None class Config: populate_by_name = True- Open Telegram
- Search for @BotFather
- Send the command
startand/newbotand follow the instructions - Once your bot is created, BotFather will give you a token.
- Save this token to your local environment so the bot can use it.
export TELEGRAM_TOKEN=8197297946:AAHVUKxdVq1b15O9-JJ2Xp6SyWVopbLdL5shttps://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html
git clone https://github.com/eslazarev/aws-lambda-telegram-bot.git cd aws-lambda-telegram-botEdit the dispatcher.py file to implement your bot's business logic. This is where you handle incoming messages and commands.
from src.infrastructure.telegram.telegram_api import send_message from src.models.telegram_request import TelegramRequest from loguru import logger async def telegram_dispatcher(telegram_request: TelegramRequest) -> None: """ Dispatcher for handling Telegram requests. :param telegram_request: TelegramRequest :return: None """ if telegram_request.message.text == "/start": logger.info(f"Received /start command from user {telegram_request.message.from_.id}") await send_message( chat_id=telegram_request.message.chat.id, text="Welcome to the bot! How can I assist you today?", reply_to_message_id=telegram_request.message.message_id, ) return # Handle other commands or messages if telegram_request.message.text: logger.info(f"Received message from user {telegram_request.message.from_.id}: {telegram_request.message.text}") await send_message( chat_id=telegram_request.message.chat.id, text=f"I received your message.\nBut I don't know how to respond yet.", reply_to_message_id=telegram_request.message.message_id, ) returnnpm install -g serverlessnpm installpip install -r requirements-local.txt(https://ngrok.com/downloads)[https://ngrok.com/downloads]
uvicorn src/entry_point_fastapi_app:app --reloadngrok http 8000Use the ngrok URL to set the webhook for your bot. Replace <ngrok_url> with the actual URL provided by ngrok.
curl -X POST "https://api.telegram.org/bot$TELEGRAM_TOKEN/setWebhook" -d "url=https://<ngrok_url>/webhook"Send a message to your bot in Telegram. You should see the request being logged in your terminal where you run the FastAPI server.
serverless deploy -r eu-central-1 --param=$TELEGRAM_TOKENUse the API Gateway URL provided by Serverless Framework to set the webhook for your bot. Replace <api_gateway_url> with the actual URL.
curl -X POST "https://api.telegram.org/bot$TELEGRAM_TOKEN/setWebhook" -d "url=https://<api_gateway_url>/"Send a message to your bot in Telegram. You should see the request being logged in your AWS CloudWatch logs.


