DEV Community

qing
qing

Posted on

How to Build a CLI Tool with Python and Click

How to Build a CLI Tool with Python and Click

How to Build a CLI Tool with Python and Click

Imagine you’re tired of typing python script.py --config file.json --verbose every time you run your script. You want a clean, professional command like myapp run --config file.json that feels like a real tool, not just a script. That’s exactly what you get when you build a CLI with Python’s Click library — a battle-tested, decorator-based framework that makes creating command-line interfaces feel almost magical.

Click isn’t just about parsing arguments; it’s about designing tools that people want to use. From auto-generated help text to type-safe parameters and nested commands, Click handles the heavy lifting so you can focus on your logic. Let’s build a real, usable CLI tool together — one you can install, run, and share today.

Why Click? (And Why Not argparse?)

Before we dive in, let’s be clear: Python’s built-in argparse works, but it’s verbose and rigid. Click, on the other hand, is:

  • Decorator-based: Just add @click.command() and you’re done.
  • Type-safe: Automatically validates and converts input types.
  • Help-ready: Generates beautiful --help output automatically.
  • Composable: Build nested groups and subcommands effortlessly.

As the official docs say, Click is “for creating beautiful command line interfaces in a composable way with as little code as necessary”[6].

Step 1: Set Up Your Project

First, create a project folder and a virtual environment:

mkdir my-cli-tool
cd my-cli-tool
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
Enter fullscreen mode Exit fullscreen mode

Now install Click:

pip install click
Enter fullscreen mode Exit fullscreen mode

We’ll also create a mycli.py file to hold our CLI logic. This keeps things modular and ready for packaging later.

Step 2: Write Your First Command

Let’s build a simple note-taking CLI that can add, list, and delete notes. Start by creating mycli.py:

import click
import json
import os

NOTES_FILE = "notes.json"

def load_notes():
    if os.path.exists(NOTES_FILE):
        with open(NOTES_FILE, "r") as f:
            return json.load(f)
    return {}

def save_notes(notes):
    with open(NOTES_FILE, "w") as f:
        json.dump(notes, f)

@click.group()
def cli():
    """My CLI Note Tool"""
    pass

@cli.command()
@click.argument("title")
@click.argument("content")
def add(title, content):
    """Add a new note."""
    notes = load_notes()
    notes[title] = content
    save_notes(notes)
    click.echo(f"Note '{title}' added!")

@cli.command()
def list():
    """List all notes."""
    notes = load_notes()
    if not notes:
        click.echo("No notes yet.")
    else:
        for title, content in notes.items():
            click.echo(f"{title}: {content}")

@cli.command()
@click.argument("title")
def delete(title):
    """Delete a note by title."""
    notes = load_notes()
    if title in notes:
        del notes[title]
        save_notes(notes)
        click.echo(f"Note '{title}' deleted.")
    else:
        click.echo(f"Note '{title}' not found.")

if __name__ == "__main__":
    cli()
Enter fullscreen mode Exit fullscreen mode

Run it:

python mycli.py add "Meeting" "Discuss Q3 goals"
python mycli.py list
python mycli.py delete "Meeting"
Enter fullscreen mode Exit fullscreen mode

You’ll get clean output, auto-generated help (python mycli.py --help), and type-checked arguments. Try typing python mycli.py add without arguments — Click will instantly tell you what’s missing.

Step 3: Make It Installable (The Professional Touch)

Right now, you’re running python mycli.py. But real tools are installed via pip. Let’s make this happen.

Create a setup.py in your project root:

from setuptools import setup

setup(
    name='mycli',
    version='1.0.0',
    py_modules=['mycli'],
    install_requires=['Click'],
    entry_points={
        'console_scripts': [
            'mycli=mycli:cli',
        ],
    },
)
Enter fullscreen mode Exit fullscreen mode

Install your package in editable mode:

pip install --editable .
Enter fullscreen mode Exit fullscreen mode

Now you can run mycli from anywhere:

mycli add "Todo" "Buy groceries"
mycli list
Enter fullscreen mode Exit fullscreen mode

This is the difference between a script and a tool. Users can install it with one line, and it behaves like any system command.

Step 4: Add Advanced Features (Optional but Powerful)

Click shines when you go beyond basics. Here are a few upgrades you can add today:

Type Validation

@click.option("--count", type=int, default=1)
def process(count):
    click.echo(f"Processing {count} items")
Enter fullscreen mode Exit fullscreen mode

Click ensures --count is an integer and defaults to 1 if omitted.

Nested Commands

@cli.group()
def db():
    """Database commands"""
    pass

@db.command()
def migrate():
    click.echo("Migrating database...")

@db.command()
def backup():
    click.echo("Backing up database...")
Enter fullscreen mode Exit fullscreen mode

Now you have mycli db migrate and mycli db backup.

Interactive Prompts

@click.option("--name", prompt="Enter your name")
def greet(name):
    click.echo(f"Hello, {name}!")
Enter fullscreen mode Exit fullscreen mode

Click will pause and ask for input if --name isn provided.

Step 5: Test and Share

Before sharing, test your CLI thoroughly:

  • Try invalid inputs (e.g., mycli add "" "content").
  • Check --help output for clarity.
  • Ensure it works on Windows, macOS, and Linux.

Then, package it for PyPI:

  1. Create a README.md with usage examples.
  2. Add a LICENSE file.
  3. Use pip install twine and twine upload dist/* to publish.

Or share it on GitHub with a simple pip install git+https://github.com/youruser/mycli.git.

You’re Now a CLI Tool Builder

You’ve gone from a script to a professional, installable CLI tool in under an hour. With Click, you get:

  • Auto-generated help
  • Type safety
  • Nested commands
  • Interactive prompts
  • Easy packaging

And you did it all with clean, readable code.

Your next step: Pick a small script you use daily and wrap it with Click. Add --help, validate inputs, and make it installable. In a week, you’ll have a toolbox of personal CLI utilities that save you hours.

Want to see more? Check out the official Click docs for advanced patterns like context objects, plugins, and custom types[6][8].

Now go build something awesome. The terminal is waiting.


💡 Related: **Content Creator Ultimate Bundle (Save 33%)* — $29.99*


💡 Related: **Content Creator Ultimate Bundle (Save 33%)* — $29.99*

Top comments (0)