Migration FAQ (2.x -> 3.0)#


This guide is still in progress.

This version introduces much many breaking changes and architectural improvements, helping to reduce global variables count in your code, provides useful mechanisms to separate your code to modules or just make sharable modules via packages on the PyPi, makes middlewares and filters more controllable and others.

On this page you can read about points that changed corresponding to last stable 2.x version.


This page is most like a detailed changelog than a migration guide, but it will be updated in the future.

Feel free to contribute to this page, if you find something that is not mentioned here.


  • Dispatcher class no longer accepts the Bot instance into the initializer, it should be passed to dispatcher only for starting polling or handling event from webhook. Also this way adds possibility to use multiple bot instances at the same time (“multibot”)

  • Dispatcher now can be extended with another Dispatcher-like thing named Router (Read more »). With routes you can easily separate your code to multiple modules and may be share this modules between projects.

  • Removed the _handler suffix from all event handler decorators and registering methods. (Read more »)

  • Executor entirely removed, now you can use Dispatcher directly to start polling or webhook.

  • Throttling method is completely removed, now you can use middlewares to control the execution context and use any throttling mechanism you want.

  • Removed global context variables from the API types, Bot and Dispatcher object, from now if you want to get current bot instance inside handlers or filters you should accept the argument bot: Bot and use it instead of Bot.get_current() Inside middlewares it can be accessed via data["bot"].

  • Now to skip pending updates, you should call the aiogram.methods.delete_webhook.DeleteWebhook method directly instead of passing skip_updates=True to start polling method.

Filtering events#

  • Keyword filters can no more be used, use filters explicitly. (Read more »)

  • In due to keyword filters was removed all enabled by default filters (state and content_type now is not enabled), so you should specify them explicitly if you want to use. For example instead of using @dp.message_handler(content_types=ContentType.PHOTO) you should use @router.message(F.photo)

  • Most of common filters is replaced by “magic filter”. (Read more »)

  • Now by default message handler receives any content type, if you want specific one just add the filters (Magic or any other)

  • State filter now is not enabled by default, that’s mean if you using state="*" in v2 then you should not pass any state filter in v3, and vice versa, if the state in v2 is not specified now you should specify the state.

  • Added possibility to register per-router global filters, that helps to reduces the number of repetitions in the code and makes easily way to control for what each router will be used.

Bot API#

  • Now all API methods is classes with validation (via pydantic) (all API calls is also available as methods in the Bot class).

  • Added more pre-defined Enums and moved into aiogram.enums sub-package. For example chat type enum now is aiogram.enums.ChatType instead of aiogram.types.chat.ChatType. (Read more »)

  • Separated HTTP client session into container that can be reused between different Bot instances in the application.

  • API Exceptions is no more classified by specific message in due to Telegram has no documented error codes. But all errors is classified by HTTP status code and for each method only one case can be caused with the same code, so in most cases you should check that only error type (by status-code) without checking error message. (Read more »)


  • Middlewares can now control a execution context, e.g. using context managers (Read more »)

  • All contextual data now is shared between middlewares, filters and handlers to end-to-end use. For example now you can easily pass some data into context inside middleware and get it in the filters layer as the same way as in the handlers via keyword arguments.

  • Added mechanism named flags, that helps to customize handler behavior in conjunction with middlewares. (Read more »)

Keyboard Markup#

Callbacks data#

Finite State machine#

  • State filter will no more added to all handlers, you will need to specify state if you want

  • Added possibility to change FSM strategy, for example if you want to control state for each user in chat topics instead of user in chat you can specify it in the Dispatcher.

  • Now aiogram.fsm.state.State and aiogram.fsm.state.StateGroup don’t have helper methods like .set(), .next(), etc.

    Instead of this you should set states by passing them directly to aiogram.fsm.context.FSMContext (Read more »)

  • State proxy is deprecated, you should update the state data by calling state.set_data(...) and state.get_data() respectively.

Sending Files#

  • From now you should wrap sending files into InputFile object before send instead of passing IO object directly to the API method. (Read more »)


  • Simplified aiohttp web app configuration

  • By default added possibility to upload files when you use reply into webhook

Telegram API Server#

  • server param was moved from Bot instance to api in BaseSession.

  • aiogram.bot.api.TELEGRAM_PRODUCTION was moved to aiogram.client.telegram.PRODUCTION.