Implementation:Langgenius Dify CLI Commands
| Knowledge Sources | |
|---|---|
| Domains | Backend, Administration, DevOps |
| Last Updated | 2026-02-12 07:00 GMT |
Overview
Flask CLI commands module providing administrative operations for managing Dify platform accounts, databases, vector stores, plugins, and data lifecycle tasks.
Description
The commands.py module defines a comprehensive set of Click-decorated CLI commands that are registered with the Flask application through ext_commands.py. Each command is a standalone function decorated with @click.command and optional @click.option decorators for parameter handling, providing interactive prompts and validation.
The commands span several administrative domains: account management (password and email resets, tenant creation), database operations (schema upgrades, vector database migrations), data lifecycle management (cleaning expired messages, clearing free-plan logs, archiving and restoring workflow runs), plugin ecosystem operations (data migration, extraction, installation), and infrastructure maintenance (orphaned file cleanup, Qdrant index management, OSS migration). Many commands operate in paginated batches to handle large datasets gracefully and include progress reporting via colored CLI output.
All commands are registered in extensions/ext_commands.py via app.cli.add_command(), making them available through flask <command-name> or equivalently uv run --project api flask <command-name> in the Dify development workflow. Several commands are restricted to the SELF_HOSTED edition and use Redis distributed locks or database transactions for safe concurrent execution.
Usage
Use these commands for platform administration tasks that cannot be performed through the web UI: resetting user credentials, migrating vector databases after configuration changes, upgrading the database schema during deployments, cleaning up expired data to reclaim storage, and managing the plugin migration pipeline. Commands are invoked via the Flask CLI runner in a properly configured application context.
Code Reference
Source Location
- Repository: Langgenius_Dify
- File: api/commands.py
- Lines: 1-2659
Signature
@click.command("reset-password", help="Reset the account password.")
@click.option("--email", prompt=True, help="Account email to reset password for")
@click.option("--new-password", prompt=True, help="New password")
@click.option("--password-confirm", prompt=True, help="Confirm new password")
def reset_password(email, new_password, password_confirm): ...
@click.command("reset-email", help="Reset the account email.")
@click.option("--email", prompt=True, help="Current account email")
@click.option("--new-email", prompt=True, help="New email")
@click.option("--email-confirm", prompt=True, help="Confirm new email")
def reset_email(email, new_email, email_confirm): ...
@click.command("reset-encrypt-key-pair", help="Reset the asymmetric key pair of workspace for encrypt LLM credentials.")
def reset_encrypt_key_pair(): ...
@click.command("vdb-migrate", help="Migrate vector db.")
@click.option("--scope", default="all", prompt=False, help="The scope of vector database to migrate, Default is All.")
def vdb_migrate(scope: str): ...
@click.command("create-tenant", help="Create account and tenant.")
@click.option("--email", prompt=True, help="Tenant account email.")
@click.option("--name", prompt=True, help="Workspace name.")
@click.option("--language", prompt=True, help="Account language, default: en-US.")
def create_tenant(email: str, language: str | None = None, name: str | None = None): ...
@click.command("upgrade-db", help="Upgrade the database")
def upgrade_db(): ...
@click.command("fix-app-site-missing", help="Fix app related site missing issue.")
def fix_app_site_missing(): ...
@click.command("convert-to-agent-apps", help="Convert Agent Assistant to Agent App.")
def convert_to_agent_apps(): ...
@click.command("add-qdrant-index", help="Add Qdrant index.")
@click.option("--field", default="metadata.doc_id", prompt=False, help="Index field.")
def add_qdrant_index(field: str): ...
@click.command("old-metadata-migration", help="Old metadata migration.")
def old_metadata_migration(): ...
@click.command("migrate-data-for-plugin", help="Migrate data for plugin.")
def migrate_data_for_plugin(): ...
@click.command("clear-free-plan-tenant-expired-logs", help="Clear free plan tenant expired logs.")
@click.option("--days", default=30)
@click.option("--batch", default=100)
@click.option("--tenant_ids", multiple=True)
def clear_free_plan_tenant_expired_logs(days: int, batch: int, tenant_ids: list[str]): ...
@click.command("clean-workflow-runs", help="Clean expired workflow runs and related data for free tenants.")
def clean_workflow_runs(before_days, batch_size, from_days_ago, to_days_ago, start_from, end_before, dry_run): ...
@click.command("archive-workflow-runs", help="Archive workflow runs for paid plan tenants to S3-compatible storage.")
def archive_workflow_runs(tenant_ids, before_days, from_days_ago, to_days_ago, start_from, end_before, batch_size, workers, limit, dry_run, delete_after_archive): ...
@click.command("restore-workflow-runs", help="Restore archived workflow runs from S3-compatible storage.")
def restore_workflow_runs(tenant_ids, run_id, start_from, end_before, workers, limit, dry_run): ...
@click.command("clean-expired-messages", help="Clean expired messages.")
def clean_expired_messages(batch_size, graceful_period, start_from, end_before, dry_run): ...
Import
from commands import (
reset_password,
reset_email,
reset_encrypt_key_pair,
vdb_migrate,
create_tenant,
upgrade_db,
fix_app_site_missing,
convert_to_agent_apps,
add_qdrant_index,
old_metadata_migration,
migrate_data_for_plugin,
clear_free_plan_tenant_expired_logs,
clean_workflow_runs,
clean_expired_messages,
)
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| str | Yes (for account commands) | Account email address for password/email reset and tenant creation | |
| new_password | str | Yes (for reset-password) | New password to set for the account |
| password_confirm | str | Yes (for reset-password) | Confirmation of the new password |
| new_email | str | Yes (for reset-email) | New email address to replace the existing one |
| scope | str | No | Scope for vdb-migrate: "all", "knowledge", or "annotation" (default: "all") |
| name | str | Yes (for create-tenant) | Workspace name for the new tenant |
| language | str | No | Language code for the new account (default: "en-US") |
| field | str | No | Index field name for Qdrant index creation (default: "metadata.doc_id") |
| days | int | No | Number of days for log retention threshold (default: 30) |
| batch / batch_size | int | No | Batch size for paginated processing (default varies by command) |
| tenant_ids | list[str] | No | Specific tenant IDs to target for cleanup/archival operations |
| before_days | int | No | Delete or archive records older than N days (default: 30 or 90) |
| start_from | datetime | No | Lower bound (inclusive) for created_at time range |
| end_before | datetime | No | Upper bound (exclusive) for created_at time range |
| dry_run | bool | No | Preview mode that shows what would be affected without making changes |
| workers | int | No | Number of concurrent workers for parallel operations (default: 1) |
Outputs
| Name | Type | Description |
|---|---|---|
| CLI stdout | str | Colored status messages indicating progress, success, or failure of each operation |
| Database side effects | N/A | Modified account records, migrated vector indexes, upgraded schema, deleted expired data |
| SystemExit(1) | int | Raised on critical failures such as database migration errors |
Usage Examples
Reset an Account Password
uv run --project api flask reset-password --email admin@example.com --new-password "NewSecure1Pass" --password-confirm "NewSecure1Pass"
Create a New Tenant
uv run --project api flask create-tenant --email user@example.com --name "My Workspace" --language en-US
Upgrade the Database Schema
uv run --project api flask upgrade-db
Migrate Vector Database
uv run --project api flask vdb-migrate --scope knowledge
Clean Expired Workflow Runs (Dry Run)
uv run --project api flask clean-workflow-runs --before-days 30 --batch-size 200 --dry-run
Clean Expired Messages
uv run --project api flask clean-expired-messages --start-from 2025-01-01 --end-before 2025-06-01 --batch-size 1000 --dry-run