Telegram Bot Python Project Structure
Python Telegram bot using python-telegram-bot. Modular handlers, conversation flows, and inline query support.
Project Directory
telegram-bot/
src/
Bot source code
__init__.py
bot.py
Application setup, handlers
handlers/
Command and message handlers
__init__.py
commands.py
/start, /help
messages.py
Text handlers
callbacks.py
Inline button callbacks
conversations.py
Multi-step flows
keyboards/
Reply and inline keyboards
__init__.py
reply.py
inline.py
services/
Business logic
__init__.py
user_service.py
api_client.py
utils/
Helper functions
__init__.py
filters.py
Custom filters
decorators.py
helpers.py
config.py
Settings from env
data/
Persistent data
.gitkeep
tests/
__init__.py
conftest.py
test_handlers.py
main.py
Entry point
pyproject.toml
.env.example
BOT_TOKEN here
.gitignore
README.md
Why This Structure?
This structure separates concerns into handlers (user interaction), keyboards (UI), services (business logic), and utils (shared helpers). Handlers are grouped by interaction type—commands, messages, callbacks, and conversations—making it easy to find and modify specific features.
Key Directories
- src/handlers/-Command and message handlers by type
- src/keyboards/-Reply and inline keyboard builders
- src/services/-Business logic and external API clients
- src/utils/-Custom filters, decorators, helpers
Getting Started
uv init telegram-bot && cd telegram-botuv add python-telegram-bot python-dotenvcp .env.example .envand add your bot token from @BotFatheruv run python main.py
Command Handlers
# src/handlers/commands.py
from telegram import Update
from telegram.ext import ContextTypes
async def start(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"Welcome! Use /help to see available commands."
)
async def help_command(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Available commands:\n/start - Start bot")
Conversation Flows
Use ConversationHandler for multi-step flows like registration or forms. Each state maps to a handler, with entry_points, states, and fallbacks defining the flow. Store conversation data in context.user_data.
When To Use This
- Building a Telegram bot with multiple commands
- Bots needing conversation flows (forms, wizards)
- Projects requiring inline keyboards and callbacks
- Teams familiar with Python async/await
Best Practices
- Use
ApplicationBuilderfor bot setup - Group related handlers in separate modules
- Use
CallbackQueryHandlerpatterns for inline buttons - Store tokens in
.env, never commit them - Use
JobQueuefor scheduled tasks
Trade-offs
- Async-only-v20+ is fully async, no sync fallback
- Webhook complexity-Requires HTTPS endpoint for production webhooks
- Rate limits-Telegram limits messages per second per chat