A production-ready Telegram bot template using aiogram 3.x with modern Python practices.
- aiogram 3.x - Modern async Telegram Bot framework
- Structured logging - Using structlog with JSON/console output
- Configuration - TOML config with Pydantic validation
- Localization - Fluent-based i18n support
- Rate limiting - Built-in throttling middleware
- Type hints - Full type annotations throughout
- Docker support - Ready for containerized deployment
- Database templates - Abstract repository pattern with SQLite example
├── bot.py # Entry point
├── config_reader.py # Configuration handling
├── config.toml # Configuration file
├── fluent_loader.py # Localization loader
├── logs.py # Logging configuration
├── filters/ # Custom filters
│ ├── chat_type.py
│ ├── find_usernames.py
│ ├── is_admin.py
│ ├── is_owner.py
│ └── member_can_restrict.py
├── handlers/ # Message handlers
│ ├── admin_actions.py
│ ├── group_events.py
│ └── personal_actions.py
├── keyboards/ # Inline keyboards
│ ├── confirm.py
│ └── pagination.py
├── middlewares/ # Middlewares
│ ├── localization.py
│ ├── throttling.py
│ └── weekend.py
├── db/ # Database layer
│ ├── base.py
│ ├── memory.py
│ └── sqlite.py
└── l10n/ # Translations
├── en.ftl
└── ru.ftl
git clone <repository>
cd tgbotbase
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/macOS
# or: venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txtEdit config.toml:
[bot]
token = "YOUR_BOT_TOKEN"
owners = [123456789] # Your Telegram user IDOr use environment variables:
cp .env.example .env
# Edit .env with your valuespython bot.py# Build and run
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down| Variable | Description | Default |
|---|---|---|
BOT_TOKEN |
Telegram bot token | Required |
BOT_OWNERS |
Comma-separated owner IDs | [] |
CONFIG_FILE_PATH |
Path to config file | config.toml |
[bot]
token = ""
owners = []
[logs]
show_datetime = true
datetime_format = "%Y-%m-%d %H:%M:%S"
show_debug_logs = true
renderer = "console" # or "json"
[localization]
default_locale = "en"
fallback_locale = "en"# handlers/my_feature.py
from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
router = Router(name="my_feature")
@router.message(Command("mycommand"))
async def my_handler(message: Message) -> None:
await message.answer("Hello!")Register in handlers/__init__.py:
from . import my_feature
def register_all_handlers(dp: Dispatcher) -> None:
# ... existing routers ...
dp.include_router(my_feature.router)# filters/my_filter.py
from aiogram.filters import BaseFilter
from aiogram.types import Message
class MyFilter(BaseFilter):
async def __call__(self, message: Message) -> bool:
return True # Your logic here# middlewares/my_middleware.py
from aiogram import BaseMiddleware
class MyMiddleware(BaseMiddleware):
async def __call__(self, handler, event, data):
# Before handler
result = await handler(event, data)
# After handler
return resultAdd translations in l10n/ directory using Fluent format:
# l10n/en.ftl
greeting = Hello, { $name }!Use in handlers:
@router.message(Command("greet"))
async def greet(message: Message, l10n: FluentLocalization) -> None:
text = l10n.format_value("greeting", {"name": message.from_user.first_name})
await message.answer(text)- aiogram - Telegram Bot framework
- @MasterGroosha - Aiogram 3 tutorials
MIT License (hell yeah!)