Library / SDK
Tishka17/aiogram_dialog avatar
Tishka17/aiogram_dialog

aiogram_dialog: a windowing model for Telegram bots

GUI framework on top of aiogram

898 stars123 forksPythonApache-2.0

At a glance

What is it?
aiogram_dialog gives an aiogram 3 bot a GUI layer with windows, reusable widgets, per-dialog state and a stack of screens that behave like a mobile application, rather than a pile of callback handlers. It is Apache-2.0 licensed and sits on top of aiogram, and the design assumes the bot is a product with an interface rather than a script with a few replies.
Who is it for?
aiogram_dialog fits a team building a Telegram bot that has to look like an application, with forms, menus, wizards and navigation that a user can go back from, and it fits a team that has already chosen aiogram 3 and wants the interface separated from the business logic. It is the wrong choice for a bot with three commands, and it is the wrong choice if you are still on aiogram 2, since the 1.x line is the only one that supports that and is described as critical fix only.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 128 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three ideas carry the whole design

The project describes itself as a framework for developing interactive messages and menus in your telegram bot like a normal GUI application, and it says it is inspired by ideas of the Android SDK and other tools. Three main ideas are listed.

The first is split data retrieving, rendering and action processing. The stated benefit is that you need nothing to do for showing the same content after some actions, and that you can show the same data in multiple ways. That is the core of the library. In a hand written bot, a callback handler usually re-renders by hand, and every place that shows a menu ends up with its own copy of the query and its own copy of the keyboard. Here a getter function loads the data, the text widget formats it, the keyboard widget renders the buttons, and the handler only processes the action. Re-rendering after an action is a consequence of the model rather than something you write.

The second is reusable widgets. The documentation says you can create a calendar or a multiselect at any point of your application without copy-pasting its internal logic. A calendar widget is a nontrivial piece of code with a date model, a grid layout, navigation and a selection state, and having it in the library rather than in every bot is the obvious win.

The third is a limited scope of context: any dialog keeps some data until closed, and multiple opened dialogs process their data separately. That last clause is the important one. Telegram bots often have a single global state, and two concurrent flows in the same chat corrupt each other. Here each dialog has its own data, scoped to that dialog, and separate dialogs do not interfere.

The workflow the documentation describes puts the user first. You think about the user, what he sees and what he does, then split that vision into reusable parts and design the bot by combining dialogs, windows and widgets, and only then add your core logic. Many components are ready to use, but you can extend and add your own widgets and even core features.

A window is a bundle of five independent parts

The declaration section is where the abstraction becomes concrete, and it is short enough to hold in your head.

Each window consists of text widgets that render the text of the message, keyboard widgets that render the inline keyboard, a media widget that renders media if needed, a message handler that is called when the user sends a message while the window is shown, data getter functions that load data from any source and can be used in the text and the keyboard, and state, which is used when switching between windows.

The example puts those pieces together:

python
from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog.widgets.text import Format, Const
from aiogram_dialog.widgets.kbd import Button
from aiogram_dialog import Window


class MySG(StatesGroup):
    main = State()


async def get_data(**kwargs):
    return {"name": "world"}


Window(
    Format("Hello, {name}!"),
    Button(Const("Empty button"), id="nothing"),
    state=MySG.main,
    getter=get_data,
)

The Format widget takes a template string and fills it from the getter's dictionary, and the Const widget carries a fixed string for a button label. The Button is given an id, which is what the framework routes the callback on.

Two rules come with the state. The documentation says to always create State inside StatesGroup, and separately that all windows in a dialog MUST have states from the same StatesGroup. Those are not style preferences, they are how the framework knows which screen the user is on, and a window with a state outside the dialog's group would be unreachable in the transition graph.

The rendering layer is described as rich text rendering using a format function or a Jinja2 template engine, so a window can be templated rather than built with string concatenation.

A dialog is a stack, and RESET_STACK is the rule that keeps it sane

The window on its own does nothing except prepare a message, and the documentation is explicit about that. To use it you need a dialog, which is a set of windows bound to states.

python
from aiogram.fsm.state import StatesGroup, State
from aiogram_dialog import Dialog, Window


class MySG(StatesGroup):
    first = State()
    second = State()


dialog = Dialog(
    Window(..., state=MySG.first),
    Window(..., state=MySG.second),
)

The dialog then has to be registered into the Dispatcher and set up:

python
from aiogram import Dispatcher
from aiogram_dialog import setup_dialogs

...
dp = Dispatcher(storage=storage)  # create as usual
dp.include_router(dialog)
setup_dialogs(dp)

And it is started through the start method of a DialogManager instance, providing the state to switch into, usually the state of the first window in the dialog:

python
async def user_start(message: Message, dialog_manager: DialogManager):
    await dialog_manager.start(MySG.first, mode=StartMode.RESET_STACK)

dp.message.register(user_start, CommandStart())

That last line of the documentation is the one to internalise. Always set mode=StartMode.RESET_STACK in your top level start command. Otherwise, dialogs are stacked just as they do on your mobile phone, so you can reach a stack overflow error.

That is a real design characteristic rather than a bug. The framework models a screen stack so that a user can press back and a nested dialog can be dismissed to the one below it, and the price is that a start command which does not clear the stack pushes a new copy of your first screen on top of whatever was there. Get the mode wrong and the bot grows dialogs without bound until it errors.

The other part of the model is the transition rules. The documentation lists different rules of transitions between windows and dialogs, such as keeping only one dialog on top of the stack or force sending a new message instead of updating one. So the framework does not decide for you whether a screen transition is an in-place edit of the same message or a new message, and that choice affects how the conversation looks to the user.

The widget catalogue is where the actual work is saved

The supported features list reads like a component inventory, and the inventory is the value.

For navigation there are inline keyboard widgets like SwitchTo, Start and Cancel for state switching, and Calendar for date selection. For stateful input there are Checkbox, Multiselect, Counter and TextInput, and the documentation says they record user actions and allow you to retrieve this data later.

For layout there are multiple button layouts: simple grouping with Group and Column, page scrolling with ScrollingGroup, and repeating of the same buttons for a list of data with ListGroup. That last one is the one that changes a bot's character. A list of forty items in a Telegram inline keyboard is not really possible, since the keyboard has a limited number of rows, so a list has to be paginated, and ScrollingGroup is the widget that does that.

There is also media support, described as sending media like a photo or video with fileid caching and handling switching to and from a message with no media. The fileid caching is the part worth noticing: Telegram assigns a file identifier to an uploaded file, and reusing that identifier is much cheaper than re-uploading.

The last item on the list is the one that changes how you build a bot at all. The framework offers an offline HTML preview for messages and a transitions diagram, and they can be used to check all states without emulating real use cases or exported for demonstration purposes.

That is a genuinely different way of working with a Telegram bot. Normally, verifying a menu means talking to the bot on a phone. Here you can render every window and every transition in a browser, look at the whole interface at once, and export the result. For a product with dozens of screens it turns UI review from a manual exercise into something you can do in front of a design document.

The package installs with pip and needs a three-line setup

The dependencies are declared in the package manifest and they are short. The runtime dependencies are aiogram at 3.14.0 or newer, jinja2, and cachetools between 4.0.0 and 6.0.0. The optional tools extra adds diagrams and aiohttp, and the optional tools extra is what the offline preview needs, since the preview script is exposed as a console entry point named aiogram-dialog-preview.

The package itself is aiogram_dialog, it requires Python 3.10 or newer, and the classifiers list 3.10 through 3.14. The licence is Apache-2.0 with the licence file declared in the manifest, and the author is Andrey Tikhonov. The version is dynamic, produced by setuptools-scm from the git metadata, and written into src/aiogram_dialog/_version.py at build time.

The repository listing shows a project with a real test setup and a documentation site. There is a .pytest.ini, a .coveragerc, a .ruff.toml, a .readthedocs.yaml, separate requirements_dev.txt and requirements_doc.txt files, a Makefile and make.bat for Sphinx, a docs directory, an example directory and a tests directory.

The example directory is worth a look before writing any code, because it is a catalogue of the library's features as runnable programs: a custom media url example, an i18n directory, an input media group, launch modes, a list group, a loading indicator, a mega example, a multistack example, scrolls, a simple example, a subdialog and a wizard. The wizard and the multistack examples are the two that show the model best, since a wizard is a multi-step flow and a multistack is the case where the stack behaviour matters.

Where aiogram_dialog is the wrong choice

Three situations rule it out, and one of them is about the host library rather than about this project.

The first is a bot with a handful of commands. If your bot answers a question, sends a link and shows a status, then the overhead of a window and dialog model is not repaid. The library's value comes from the number of screens, not from the sophistication of any one of them.

The second is aiogram 2. The version status section is explicit: v2.x is the actual release and supports aiogram v3.x, while v1.x is the old release, supports aiogram v2.x, and is critical fix only. So the decision to use this framework is coupled to a decision about which major version of aiogram you run, and a team on aiogram 2 is choosing a line that receives fixes only for critical problems.

The third is a bot whose interface is genuinely a conversation rather than a menu. The framework is built for a visual, navigable interface with screens you go back from. If the interaction is a free text exchange with a language model, a form, and a couple of replies, then there is no window stack to manage and the model is unnecessary weight.

There is a fourth practical constraint that follows from the architecture. The whole design assumes one user, one chat, one active flow, and the framework's correctness depends on the state machine you declare. The rules are strict: all windows in a dialog must have states from the same StatesGroup, a state must always be created inside one, and the start command must reset the stack. A team that writes bots casually, without a state discipline, will find that the framework's rules land on them as runtime errors rather than as type errors, and the stack overflow case is the one the documentation calls out by name.

The fair comparison is not another Telegram library but the plain aiogram approach, where a handler sends a message and a callback query handler edits it. That approach is more code and less structure, and for a bot with twenty screens the structure wins.

The maintenance record is the thing to check before you start

The project is Apache-2.0 licensed and hosted on Read the Docs at aiogram-dialog.readthedocs.io, with a Telegram channel linked from the README. The recent releases are 2.6.0 on 2026-03-22, 2.5.0 on 2026-02-24 and 2.4.0 on 2025-07-08.

Two details in the project record are worth noting. The default branch is develop, not master, so a clone gives you the development line rather than the last release, and the README points at the master branch for the licence file, which means the two branches are maintained separately.

The last push to the repository was on 2026-06-17, and the repository is not archived. That is a gap of roughly four months from the present date, and it sits just inside the window where a project can still be described as receiving work but where the tagged releases have not moved since March. For a library that other people's bots depend on at runtime, that is the number to watch, because the absence of a new release means the fixes are on develop rather than on a version you can pin.

The dependency on aiogram is the other thing to verify. The manifest requires aiogram 3.14.0 or newer, and aiogram is a fast moving project in its own right, so a bot that pins aiogram_dialog will also be pinning aiogram, and the two have to be compatible. The version status table in the README is about the aiogram major version, and the manifest is about the aiogram minor version, and both constraints apply at once.

What the project offers in exchange is a coherent, opinionated model of how a bot interface should be structured, a set of widgets that cover the common cases, and a preview tool that lets you look at the whole interface without a phone in your hand.

Editorial conclusion

aiogram_dialog fits a team building a Telegram bot that has to look like an application, with forms, menus, wizards and navigation that a user can go back from, and it fits a team that has already chosen aiogram 3 and wants the interface separated from the business logic. It is the wrong choice for a bot with three commands, and it is the wrong choice if you are still on aiogram 2, since the 1.x line is the only one that supports that and is described as critical fix only. Before adopting it, read the version status section, because the v1 and v2 lines are not interchangeable, and check the states rule, since all windows in a dialog must share a StatesGroup and a state must always be created inside one.

Frequently asked questions

What is aiogram_dialog and what does it add to aiogram?

It is a framework for developing interactive messages and menus in a Telegram bot like a normal GUI application, inspired by the Android SDK. It splits data retrieving, rendering and action processing, provides reusable widgets such as Calendar, Multiselect, Checkbox, Counter and TextInput, and gives each dialog its own scoped data so multiple open dialogs do not interfere.

Which versions of aiogram does aiogram_dialog support?

The version status section states that v2.x is the actual release and supports aiogram v3.x, while v1.x is the old release supporting aiogram v2.x with critical fix only. The package manifest requires aiogram 3.14.0 or newer and Python 3.10 or newer.

How do I start a dialog in aiogram_dialog?

You call the start method of a DialogManager instance with the state to switch into, usually the state of the first window. The documentation insists you always set mode=StartMode.RESET_STACK in your top level start command, because otherwise dialogs stack the way they do on a phone and you can reach a stack overflow error.

What are the rules for states in aiogram_dialog?

Always create State inside StatesGroup, and all windows in a dialog must have states from the same StatesGroup. The states are what the framework uses to know which screen the user is on and what transitions are possible.

Can I preview an aiogram_dialog interface without a Telegram account?

Yes. The project offers an offline HTML preview for messages and a transitions diagram, which can be used to check all states without emulating real use cases or exported for demonstration purposes. The preview is exposed as the aiogram-dialog-preview console script, and the tools extra adds diagrams and aiohttp.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. Tishka17/aiogram_dialog on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tishka17-aiogram-dialog.svg)](https://hysenlabs.com/projects/tishka17-aiogram-dialog)

Was this useful?