CLI tool
tmbo/questionary avatar
tmbo/questionary

questionary: readable command line prompts without writing a TUI

Python library to build pretty command line user prompts ✨Easy to use multi-select lists, confirmations, free text prompts ...

2,185 stars118 forksPythonMIT

At a glance

What is it?
A thin, MIT licensed layer over prompt_toolkit that gives Python scripts text, password, confirm, select, checkbox, path and autocomplete prompts in a few lines. The interesting parts are dependent selects and block search, not the text box.
Who is it for?
questionary is the right tool when a Python tool needs to ask two or three questions before doing its real work, and writing that with raw prompt_toolkit or argparse input calls would take a page of code per prompt. Its coverage of the common cases is complete enough that you will not hit a missing prompt, and its dependency surface is one library, so installation stays painless.
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 52 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 8, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A prompt_toolkit wrapper with a deliberately small API

prompt_toolkit is one of the best terminal interface libraries available for Python, and it is also the one most people find intimidating. questionary is the layer that makes it approachable: every prompt type is a function call, and the return value is the answer.

python
import questionary

questionary.select(
    "What do you want to do?",
    choices=[
        'Order a pizza',
        'Make a reservation',
        'Ask for opening hours'
    ]).ask()  # returns value of selection

That call constructs the prompt; the ask method on the end runs it and returns the selection, or None if the user cancelled. The pattern repeats for every type, and the README shows the full cast in one block: text, password, confirm, select, rawselect, checkbox and path.

The library also ships a helper for printing formatted text, which the README describes as being for when you want to dress up printed messages. That is a small thing to mention and a small thing that matters, because a script that prompts nicely and then prints an unstyled wall of text looks broken by comparison.

Provenance is documented rather than assumed. The README credits it as based on work by Oyetoke Toby on PyInquirer and by Mark Fink on whaaaaat, with Tom Bocklisch and Kian Cross as authors and maintainers. Copyright is recorded as 2021 Tom Bocklisch, and the repository tree carries a NOTICE file alongside the MIT LICENSE, which is the usual evidence of an upstream you should keep in mind if you are vendoring this.

One pip command, and a Python floor that moved

Installation is a single line:

bash
pip install questionary

The packaging details that matter are in pyproject.toml rather than the README, and they are worth reading before you pin anything. The project uses poetry-core as its build backend, declares version 2.1.0, and requires Python 3.10 or newer. The classifiers list 3.10 through 3.14 explicitly, and black is configured to target that same range.

The floor is worth noting because it moved. Older releases of questionary supported Python 2 alongside 3, and a project pinned to an old interpreter would not be able to take this version at all. The dependency count is the other thing to check: exactly one runtime requirement, prompt_toolkit, with a range of 2.0 up to but not including 4.0. That range spans two major versions of the underlying library, so a resolution in your environment could land prompt_toolkit on 2.x or 3.x depending on what else is installed. Nothing in questionary's own metadata prevents the older pairing, so if you are debugging a styling or keybinding difference, the prompt_toolkit version is the first thing to check.

Development extras are grouped separately, which keeps the install light: a docs group with Sphinx and a Read the Docs theme, and a dev group with pytest, coverage tooling, mypy and pre-commit hooks.

select, rawselect and checkbox differ in ways the names hide

Two of the prompt names are easy to confuse. select renders a numbered list with the current choice highlighted, and the numbers are the first character of each line, so you can jump by typing a digit. rawselect is described separately in the documentation as its own type, and the difference is that rawselect uses no short keys and no scrolling indicator, presenting the choices as a plain list where only the arrow keys move the selection.

That is a small distinction that changes how a prompt feels in front of a large choice list, which is why the project keeps them apart rather than adding a flag.

checkbox is the multi-select variant, and the examples directory shows two configurations worth knowing about. One example uses separators to group related choices with a non-selectable divider, and another pairs the checkbox with search, so a long list of options can be filtered as you type. There is also a select_search example, applying the same idea to a single-choice list. If your prompt has more than a dozen options, the searchable variants are the reason to prefer questionary over hand-rolling a numbered menu, because they remove the need for the user to scroll and count.

The path prompt deserves its own mention. It asks for a file or directory location with completion, which is the kind of thing that looks trivial in a library and takes real work to get right, particularly when the process runs somewhere other than the user's shell.

Dependent selects and autocomplete, the features that justify the dependency

The basic prompts are replaceable with anything. Two of the features are not.

The first is dependent selects, which the README does not describe but the examples directory carries as dependent_selects.py. A prompt whose choices depend on an earlier answer is the case every hand-rolled CLI handles badly, usually by asking twice or by printing a fixed list and hoping. Building it from questionary primitives is straightforward: ask the first question, take the returned value, and use it to compute the choices for the second.

The second is autocomplete, listed among the supported prompt types. The examples directory includes an ants-themed example for it, which suggests a fuzzy search over a growing list, and the README links to a separate documentation section for that type rather than folding it into the general text prompt.

None of this is exotic, and that is the point. The value is that these interactions are expressed in one line of Python instead of a state machine with callbacks, and that the same rendering and key handling applies to every prompt in the script. The cost is the dependency itself: a CLI that only asks one yes or no question has no business importing prompt_toolkit, and would be better served by a plain input call or a flag parser.

The examples directory is the documentation that matters

The tree carries more than twenty example scripts under examples/, and they cover more ground than the README does. Beyond the prompt types there are files for advanced_workflow.py, checkbox_toppings.py, password_git.py, password_confirm.py, confirm_continue.py, text_phone_number.py, project_path.py, select_action.py, rawselect_action.py and simple_print.py. The naming convention is consistent, one file per idea, and readme.py appears to hold the snippet used in the README itself.

Two of them point at real use cases rather than API tours. password_git.py is the obvious one: asking for a git identity is a genuine prompt problem with validation attached. confirm_continue.py suggests destructive-operation confirmation. Those two are the files to read if you are deciding whether the library handles your case, because they show the library doing something useful rather than demonstrating a method signature.

Build and quality tooling is Poetry based and lives in the Makefile, which is conventional and complete: install pulls in the docs group, develop installs pre-commit hooks, lint runs the hooks across the tree, test runs pytest with coverage scoped to the questionary package, docs builds the Sphinx HTML, and livedocs runs sphinx-autobuild for iteration. The docs themselves build through a separate Makefile in docs/, and Read the Docs configuration is in .readthedocs.yml with the published site on questionary.readthedocs.io.

Adoption evidence is thin in the way most small library READMEs are thin. The README names one user, Rasa, with a logo. That is a signal that the library survives contact with a real project, and not much more than that.

Version 2.1.0, no GitHub releases, and a help text that names the wrong tool

Two small inconsistencies are worth flagging because both send you looking in the wrong direction.

The first is in the Makefile. The help text describes the types target as checking for type errors using pytype. The target itself does not do that:

bash
types:
	poetry run mypy --version
	poetry run mypy questionary

mypy is the checker actually in use, and pyproject.toml carries a mypy configuration section with ignore_missing_imports, warn_redundant_casts and warn_unused_ignores enabled, plus mypy in the dev dependency group. There is no pytype anywhere in the packaging metadata. So the help line is stale text and the target is the accurate description.

The second is about releases. The repository publishes version 2.1.0 to PyPI, and the README carries a PyPI version badge, but there are no GitHub releases published in this repository at all. If you are looking for a changelog or upgrade notes on GitHub, there is nothing to find; the source of truth for what shipped is the package on PyPI and the commit history. The version string lives in pyproject.toml rather than in a dedicated file or a tag-based scheme, which is normal for a Poetry project but does mean the README badge and the package index are your only quick version checks.

For status, the classifier in pyproject.toml records the project as Beta, at version 2.1.0. The last push was on 2026-08-18 and the repository is not archived. Topics give almost nothing to go on: the only tag is hacktoberfest, which says more about a contribution drive than about the library's purpose.

Editorial conclusion

questionary is the right tool when a Python tool needs to ask two or three questions before doing its real work, and writing that with raw prompt_toolkit or argparse input calls would take a page of code per prompt. Its coverage of the common cases is complete enough that you will not hit a missing prompt, and its dependency surface is one library, so installation stays painless. What you accept is that it is a linear conversation with a human at a terminal: there is no layout engine for dashboards, no non-interactive mode to fall back on when nobody is there to answer, and no way to script a run without either piping stdin or stubbing the prompt. Check the prompt_toolkit version your environment already pins before upgrading, since the package accepts a range spanning two major versions, and read a dependent_selects example if your prompts depend on earlier answers. For anything with a layout, use prompt_toolkit directly.

Frequently asked questions

What is the difference between questionary and prompt_toolkit?

prompt_toolkit is the terminal interface library underneath, and questionary is a convenience layer over it with one function per prompt type. questionary adds a single runtime dependency on prompt_toolkit and exposes text, password, path, confirm, select, rawselect, checkbox and autocomplete prompts. If you need a custom layout, key binding or full-screen application, go to prompt_toolkit directly rather than through questionary.

What is the difference between select and rawselect in questionary?

Both present a list of choices, but they differ in the interaction they offer. select renders numbered choices you can jump to by typing a digit, while rawselect omits the short keys and the scrolling indicator, leaving arrow keys as the way to move. Choose rawselect when the numbered shortcuts get in the way of a long or irregularly shaped list.

How do I install questionary and which Python versions does it support?

Run pip install questionary. The packaging metadata declares Python 3.10 or newer, with classifiers covering 3.10 through 3.14, and the current version is 2.1.0. The only runtime dependency is prompt_toolkit, accepted across versions 2.0 up to but not including 4.0.

How do I make one questionary prompt depend on an earlier answer?

ask returns the answer, so use that return value to compute the choices for the next prompt. The repository ships an examples/dependent_selects.py demonstrating the pattern, and there is also an advanced_workflow.py example for longer sequences. There is no special dependency mechanism to learn, which is the usual reason hand-rolled CLI prompts get awkward at this point.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. tmbo/questionary 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/tmbo-questionary.svg)](https://hysenlabs.com/projects/tmbo-questionary)