interactions.py: a Discord bot framework built around async Python
A highly extensible, easy to use, and feature complete bot framework for Discord
At a glance
- What is it?
- interactions.py is a Python framework for Discord bots and web applications, distributed on PyPI as discord-py-interactions, with full API coverage, a TTL cache, rate-limit handling and automated command synchronisation. Prefixed commands, hot reloading, Sentry, paginators and a debug suite all ship as optional extensions loaded with a single call.
- Who is it for?
- Adopt interactions.py if you are building a Discord bot in Python and want async-native calls, slash commands with automatic registration, and optional features loaded on demand rather than carried as dependencies. Do not adopt it for a bot that only needs prefixed text commands, since that support lives in an extension rather than the base library, and do not build on the 6.0 release candidate unless you are prepared for breaking changes.
- Can I use it commercially?
- Yes. MIT 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 3 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the framework is, and where it came from
interactions.py is described as a highly extensible, easy to use and feature complete framework for Discord, and the README expands that into a framework for Python-powered Discord bots and web applications alike. The project calls itself the culmination of years of experience with Discord's APIs and bot development, built from the ground up with community feedback in mind, and it aims to provide a modern and intuitive set of language bindings.
The naming carries a bit of history. The import name is interactions, the distribution on PyPI is discord-py-interactions, and the project lives in the interactions-py GitHub organisation with a repository named interactions.py. The PyPI project also carries a second distribution, discord-py-slash-command, as the README's download badge indicates, so the framework has been published under more than one name over its life.
The package metadata describes it as a Python API wrapper for interactions, and that phrase captures the core idea. Discord's model is built around interactions, a slash command invocation, an autocomplete request, a button press, a modal submission, and the framework treats those as first-class objects you decorate functions with rather than as raw payloads you parse from a gateway event.
The author field in the project metadata names LordOfPolls, with a matching email, which tells you this is a project with a principal maintainer rather than a committee, and the hacktoberfest topic tag on the repository says the same thing about how outside contributions arrive.
The feature list, and what each claim costs you
The README lists six headline features, and each one is a specific engineering commitment rather than a slogan.
Full coverage of the Discord API means the wrapper does not leave you to reach for raw HTTP when a new endpoint appears. The dynamic cache with TTL support means fetched objects are cached and expire on their own, which matters because the API charges for reads and a bot that refetches a guild list on every command burns its rate limit. Proper rate-limit handling is the same concern handled at the transport level rather than the application level. Feature parity with most other Discord API wrappers is the compatibility argument: a bot written against another library can often be ported by changing imports.
Fully automated command synchronisation is the one that saves the most day-to-day work. Discord stores a bot's slash commands server-side, so a command added in Python has to be pushed to Discord or it simply does not appear. Having that happen as part of startup removes a manual step that is easy to forget and tedious to do.
The cache and the rate-limit handling deserve one more sentence together, because they are the two features you only appreciate when they are missing. A bot that ignores both will start throwing HTTP 429 responses, and the fix is rarely obvious from the error alone.
Beyond the core, the framework provides optional extensions, which the README frames as the way to add features without bloating the base install. The set of extras is defined in the project metadata as named groups: voice, speedup, sentry, jurigged, console and docs, plus an all group that chains them together and separate test and dev groups.
Installing and starting a bot
The getting started path is a pip install and a short script:
`pip install -U discord-py-interactions`
import interactions
bot = interactions.Client()
@interactions.listen()
async def on_startup():
print("Bot is ready!")
bot.start("token")The shape of that script is the shape of the whole API. You create a Client, decorate an async function with a listener decorator, and start the client with a token. The listener decorator handles the dispatch, so your handler receives the event object rather than a raw payload.
The runtime requirements are stated in the project metadata: Python 3.10 or newer, and the supported range is listed as >=3.10,<4.0. The base dependencies are aiohttp for the HTTP and websocket layer, attrs for the data model, discord-typings for the Discord type definitions, tomli for reading configuration, emoji and croniter for scheduled tasks, and mypy as a dependency for type checking support.
One dependency in the requirements file is worth noting. audioop-lts is required on Python 3.13 and above, because audioop was removed from the standard library in that version. That is the sort of detail that shows a project tracking new Python releases, and it also tells you the voice extension has real dependencies on audio processing.
The documentation is built with MkDocs, with an mkdocs.yml at the root and a readthedocs.yaml for the hosted version. There is a guides section starting at Getting Started, and the README points to a Discord server for support.
Extensions: prefixed commands, hot reloading, paginators and more
The extension system is the part of the design that most shapes how the framework feels in use, and the README is explicit that the base library does not handle prefixed commands by default.
That is a deliberate choice with a rationale. Prefixed commands, message commands and legacy commands are the older style where a user types a trigger character and a name. The library will not handle them unless you load the extension, and the reasoning is that the modern interaction model is the one the framework is built around. For a new bot this is the right default. For someone maintaining a bot with a decade of prefixed commands, it means one extension to keep the old style working.
The extension that gets attention is Jurigged, a hot reloading extension that updates the bot without reboots. For a bot under active development that is a large quality-of-life difference, since the usual cycle otherwise involves a restart for every edit.
The others fill in common gaps. The debug extension is a debug and utilities suite for building bots. Sentry integrates Sentry.io error tracking with what the README calls a single line of setup. The console extension adds aiomonitor support and enables command line commands over a web interface, which is useful for poking at a running bot remotely. The paginators extension lets you create multi-page embeds without implementing that behaviour yourself, which removes a piece of UX work that every bot ends up writing.
Loading any of them is one call:
`bot.load_extension("extension")`
The metadata shows how the extras map to installs: the voice group brings PyNaCl and cryptography, the speedup group brings aiodns, orjson, Brotli, faust-cchardet and uvloop, and uvloop is excluded on Windows by the platform marker.
Repository layout and how the package is assembled
The tree shows a project that maintains both a modern build path and a compatibility path.
The interactions/ directory is the package itself. main.py is the entry point. pyproject.toml is a Poetry configuration with the version, the author and the dependency groups, and poetry.lock pins the resolved versions. Alongside that sits setup.py, which reads pyproject.toml with tomli and hands the version, description, long description and classifiers to setuptools, with install_requires taken from requirements.txt. setup.cfg and MANIFEST.in are present too.
So the project ships both a Poetry-managed project definition and a setuptools-compatible install path, which is why the same distribution can be installed with pip under either mechanism and why requirements.txt exists alongside the Poetry groups. The extras are defined in setup.py by chaining group lists together, with an all extra that flattens voice, speedup, sentry, jurigged and console into one list, a docs extra adding the MkDocs toolchain with a pinned griffe, a tests extra with pytest, pytest-asyncio, pytest-cov, python-dotenv and typeguard, and a dev extra combining tests, docs and pre-commit.
The remaining directories are the ordinary ones. docs/ holds the documentation source, examples/ holds a bot.py sample, tests/ holds the test suite, and there are separate requirements files for docs and lint alongside the runtime requirements. The pre-commit configuration and a .editorconfig at the root, plus the black code style badge in the README, describe the formatting rules the project enforces.
One detail in the classifiers is worth noting for anyone deciding on stability: the package declares Development Status 5, Production/Stable.
Limits: the 6.0 transition, the extension boundary and the Discord API itself
Several limits are visible in what the README and the metadata document.
The first is the version gap. The tagged releases are 6.0.0rc1 from 2026-06-04, 5.16.0 from 2026-02-02 and 5.16.0rc3 from 2025-12-17, while the project metadata still carries version 5.16.0 and the default branch is named stable rather than main. The last push to the repository was on 2026-10-19, so work continues past the release candidate. A framework at a 6.0 release candidate with a stable branch on the previous line is in the middle of a transition, and adopting the candidate means accepting whatever breaking changes 6.0 carries.
The second is the extension boundary, which is a real constraint rather than a preference. Prefixed commands do not work in the base library. If your bot needs both interaction commands and legacy text commands, you are running two systems, and the prefixed command extension has its own registration behaviour and annotation support to learn.
The third is that everything depends on Discord. The API coverage claim is a strength, and it is also a coupling: the framework can only be as current as Discord's own changes, and a bot that depends on the framework's abstraction of a particular endpoint is affected by how that abstraction evolves.
The fourth is that this is a library for bots and web applications, not a hosting platform. There is no mention of scaling, sharding or deployment in the README. A large bot with many guilds will need to think about concurrency and connection handling, and the framework's job ends at the API surface.
A fifth point is about the optional extras and their weight. The voice group pulls PyNaCl and cryptography, the speedup group pulls uvloop and a character detection library, and the docs group pulls the whole MkDocs toolchain. Each is opt-in, which is the point, but the all extra deliberately pulls every one of them together, and that install is heavier than the base.
interactions.py against discord.py and against writing against the raw gateway
Two comparisons clarify the choice.
The first is against discord.py, the long-established library in the same space. The difference in approach is in what the framework makes central. A wrapper built around interactions makes the interaction types, slash commands, autocompletes, buttons and modals the units you program in, and the cost is that the older prefixed command style is separated out into an extension. A wrapper built around messages and gateway events makes those central instead. Neither is better in the abstract; they suit different bots.
The other difference is implementation language. This framework is async-native throughout, built on aiohttp, and its classifiers list the AsyncIO framework. For a bot that must handle many concurrent events and many concurrent HTTP calls, that is the shape you want.
The second comparison is against writing against the raw gateway yourself. This is a real option, since Discord publishes its own documentation and the protocol is not secret. Doing it means implementing the websocket connection and its resume logic, the rate-limit buckets, the heartbeat, the gateway intents, the HTTP endpoints, the object model and the command synchronisation. Each of those is a known problem with known answers, and each is a place where a subtle bug produces a bot that works until it does not.
The reason to write it yourself is control, and sometimes that is the right answer. If you need a Discord feature the wrapper has not modelled, or you want the smallest possible dependency footprint, or you are learning the protocol properly, then implementing it is instructive. The reason to use a framework is that the plumbing is the part you should not be writing, and the choice between the two wrappers above should be made on how each one handles the interaction model you actually want.
A third path worth naming is writing a small bot on an existing framework that already provides what you need, or using the hosted builder tools Discord itself offers for simple cases. Those are appropriate when the bot's requirements are modest and the code is not going to be maintained by a developer.
Editorial conclusion
Adopt interactions.py if you are building a Discord bot in Python and want async-native calls, slash commands with automatic registration, and optional features loaded on demand rather than carried as dependencies. Do not adopt it for a bot that only needs prefixed text commands, since that support lives in an extension rather than the base library, and do not build on the 6.0 release candidate unless you are prepared for breaking changes. Verify first that your Python is 3.10 or newer, that you understand what the extension extras pull in, and that the version on PyPI matches the documentation you are reading.
Frequently asked questions
How do I install interactions.py and start a Discord bot?
Install it with pip install -U discord-py-interactions, then create an interactions.Client, decorate an async function with @interactions.listen(), and call bot.start with your token. The project supports Python 3.10 and newer.
Does interactions.py support prefixed commands?
Not in the base library. The README states that by default the library will not handle prefixed, message or legacy commands, and that a separate extension provides them with automatic command registration and annotation support. You load it with bot.load_extension.
What optional extras does interactions.py provide?
The project metadata defines groups for voice, speedup, sentry, jurigged and console, plus an all extra that combines them, and separate docs, tests and dev groups. The README describes them as a hot reloading extension, Sentry error tracking, a console extension with aiomonitor, paginators for multi-page embeds and a debug suite.
Official sources
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.
[](https://hysenlabs.com/projects/interactions-py-interactions-py)Was this useful?