A production-ready Telegram bot template built with Node.js, TypeScript, MongoDB, and Docker. Includes auto-tunneling via ngrok for seamless local development with webhooks.
- ποΈ TypeScript β Fully typed codebase with strict mode
- π MongoDB + Mongoose β Database ready out of the box
- π― grammY β Modern, fast Telegram Bot framework
- π Auto ngrok tunneling β Webhooks work locally without manual setup
- π³ Docker & Docker Compose β One-command dev environment with hot reload
- π 3 bot modes β Polling, webhook, and auto-ngrok (auto-detected)
- π Graceful shutdown β Clean cleanup of bot, tunnel, and server
- β‘ Hot reload β Instant feedback during development
βββ src/
β βββ index.ts # Entry point β mode detection & server setup
β βββ bot.ts # Bot commands & message handlers
β βββ config.ts # Environment config loader
β βββ db/
β βββ connection.ts # MongoDB connection handler
βββ .env.example # Environment variables template
βββ docker-compose.yml # Docker services (app + MongoDB)
βββ Dockerfile # Multi-stage build (dev + prod)
βββ tsconfig.json # TypeScript configuration
βββ nodemon.json # Nodemon config for Docker hot reload
βββ package.json
- Node.js v20+
- MongoDB (local or Atlas) β or just use Docker
- A Telegram bot token from @BotFather
Click the "Use this template" button on GitHub, or clone it:
git clone https://github.com/YOUR_USERNAME/telegram-bot-boilerplate.git
cd telegram-bot-boilerplatenpm installcp .env.example .envEdit .env with your values:
BOT_TOKEN=your_bot_token_here
MONGO_URI=mongodb://localhost:27017/telegram-bot
PORT=3000
NGROK_AUTHTOKEN=your_ngrok_authtoken_here # Optional, for webhook modenpm run devThat's it! π Send /start to your bot on Telegram.
The bot automatically selects the best mode based on your environment variables:
| Priority | Condition | Mode | Best For |
|---|---|---|---|
| 1 | WEBHOOK_URL is set |
Production Webhook | Deployed servers |
| 2 | NGROK_AUTHTOKEN is set |
Auto Ngrok Tunnel | Local dev with webhooks |
| 3 | Neither is set | Long Polling | Simplest local dev |
No public URL needed. The bot polls Telegram for updates:
BOT_TOKEN=your_token
# No WEBHOOK_URL or NGROK_AUTHTOKENAutomatically creates a public URL via ngrok and sets the webhook:
BOT_TOKEN=your_token
NGROK_AUTHTOKEN=your_ngrok_tokenGet your free auth token at dashboard.ngrok.com
Uses your own public URL:
BOT_TOKEN=your_token
WEBHOOK_URL=https://your-domain.comdocker-compose upThis starts:
- App container β with hot reload via volume mounts
- MongoDB container β persistent data in a Docker volume
Edit files in src/ and changes reflect instantly.
docker build --target production -t telegram-bot .
docker run --env-file .env telegram-bot| Script | Description |
|---|---|
npm run dev |
Start with hot reload (tsx watch) |
npm run dev:docker |
Start with hot reload in Docker (nodemon) |
npm run build |
Compile TypeScript to dist/ |
npm start |
Run compiled production build |
Edit src/bot.ts:
bot.command("ping", async (ctx) => {
await ctx.reply("π Pong!");
});Create src/models/user.ts:
import mongoose from "mongoose";
const userSchema = new mongoose.Schema({
telegramId: { type: Number, required: true, unique: true },
username: String,
firstName: String,
createdAt: { type: Date, default: Date.now },
});
export const User = mongoose.model("User", userSchema);Use it in your bot:
import { User } from "./models/user.js";
bot.command("start", async (ctx) => {
await User.findOneAndUpdate(
{ telegramId: ctx.from?.id },
{
username: ctx.from?.username,
firstName: ctx.from?.first_name,
},
{ upsert: true },
);
await ctx.reply("Welcome! You've been registered. π");
});| Technology | Purpose |
|---|---|
| grammY | Telegram Bot framework |
| Mongoose | MongoDB ODM |
| tsx | TypeScript execution & watch mode |
| @ngrok/ngrok | Programmatic tunneling |
| Docker | Containerization |
This project is licensed under the MIT License.
Made with β€οΈ β Happy bot building!