CLI Workflows

Purpose and Scope

The Dub CLI is a small command-line surface for everyday link operations against the Dub API. Its README describes the package as a CLI for easily shortening URLs with the Dub API, and the command registry presents the executable as a tool for shortening links with Dub. In practice, the workflows are broader than one-off shortening: users authenticate, inspect their local credentials, choose a workspace domain, create short links, and search existing links. This page explains those common flows in the order a new user or contributor is likely to use them, while mapping each behavior back to the command modules that implement it.

Sources: packages/cli/README.md, packages/cli/src/index.ts

Dub itself is a link attribution platform where short links, conversion analytics, and affiliate-program workflows are connected. The CLI should be understood as a developer-friendly entry point into that larger platform rather than as a standalone link database. The source-backed commands here focus on link and domain tasks: authentication requests link and domain scopes, domain selection persists a preferred domain in local configuration, link listing uses the Dub SDK, and link creation delegates to a link API helper. That division lets the CLI stay compact while using the same product primitives surfaced in the dashboard and API.

Sources: packages/cli/src/commands/login.ts, packages/cli/src/commands/domains.ts, packages/cli/src/commands/links.ts, packages/cli/src/commands/shorten.ts

Relevant Source Files

  • packages/cli/README.md — documents the public command list, local development loop, and production-like linking workflow for the CLI package.
  • packages/cli/src/index.ts — defines the executable entry point, Commander program name, description, version flag, signal handling, and command registration.
  • packages/cli/src/commands/login.ts — implements browser-based OAuth login with a local callback URL and the requested Dub API scopes.
  • packages/cli/src/commands/config.ts — implements the command that reads and displays the local CLI configuration as colorized JSON.
  • packages/cli/src/commands/domains.ts — implements interactive domain selection by fetching domains, validating the selected slug, and saving it to config.
  • packages/cli/src/commands/links.ts — implements workspace link search and listing through the generated Dub client.
  • packages/cli/src/commands/shorten.ts — implements interactive and argument-based short-link creation.

Command Entry Point and Public Command Set

The executable is registered with Commander under the name dub, includes a description, and exposes -v, --version for version output. It also installs signal handlers for SIGINT and SIGTERM, so terminal interruptions exit cleanly rather than leaving the process hanging. The entry point adds five command modules: login, config, domains, shorten, and links. That means the workflows documented in the README are not only documentation promises; they are the command tree that the binary actually parses at runtime.

Sources: packages/cli/src/index.ts, packages/cli/README.md

The README lists the public commands in user-facing terms. dub login logs into the Dub platform, dub config shows configured workspace credentials, dub domains configures the workspace domain, dub shorten [url] [key] creates a short link, and dub links [options] searches workspace links. The link search command supports a search option and a limit option, with a default result size of ten in the implementation. The README also includes dub help [command], which is provided by Commander rather than a custom command module.

Sources: packages/cli/README.md, packages/cli/src/commands/links.ts

Workflow 1: Authenticate with Dub

Start with authentication because the link and domain commands depend on configuration that contains an access token. The login command creates a high-entropy code verifier, sets the redirect URI to a localhost callback, asks the OAuth client for an authorization URL, and opens that URL in the user’s browser. The requested scopes are links.read, links.write, and domains.read, matching the CLI’s visible duties: listing links, creating links, and fetching domains for selection. A spinner first reports that the browser is opening and then switches to waiting for authentication while the callback server completes the OAuth exchange.

Sources: packages/cli/src/commands/login.ts

dub login

This flow has a few operational implications. Because the callback URL is local, the command expects to run on a machine where the browser and the CLI process can cooperate through the localhost callback. Because the scopes are intentionally limited, the CLI is not asking for broad workspace administration permissions in the visible implementation. Because errors are routed through a shared error handler, failures in browser opening, authorization URL generation, or callback setup should surface through the same user-facing error path as other commands. After login succeeds, subsequent commands can rely on persisted configuration rather than prompting for credentials each time.

Sources: packages/cli/src/commands/login.ts

Workflow 2: Inspect Local Configuration

After logging in, use the configuration command to verify what the CLI has stored locally. The config command starts an activity spinner, calls the configuration reader, marks retrieval as successful, and prints the configuration object as formatted, colorized JSON. This command is intentionally read-only in the supplied implementation: it does not mutate credentials, choose a new workspace, or refresh tokens by itself. Its primary purpose is confidence and troubleshooting. When a later link or domain command behaves unexpectedly, dub config is the first low-risk check to confirm that the CLI sees the expected local state.

Sources: packages/cli/src/commands/config.ts

dub config

The output shape depends on the shared configuration helper, but the workflow expectation is clear from the command text and surrounding commands. Domain selection writes a domain value, link listing reads an access_token, and shortening first checks that configuration exists. Seeing the stored JSON therefore helps users distinguish authentication problems from input problems. If the config command cannot retrieve configuration, it stops the spinner and passes the exception to the common error handler. That behavior keeps failed configuration reads visually distinct from successful reads, which print blank lines around the colorized JSON for readability.

Sources: packages/cli/src/commands/config.ts, packages/cli/src/commands/domains.ts, packages/cli/src/commands/links.ts, packages/cli/src/commands/shorten.ts

Workflow 3: Choose a Workspace Domain

Run the domains command when you want the CLI to use a particular short-link domain for link creation workflows. The command fetches available domains through the domain API helper, turns each returned slug into an interactive select choice, and validates the selected value with a schema requiring a minimum length. Once a domain is selected, it writes the domain into local configuration and prints a success message. This makes domain configuration an explicit setup step rather than an invisible default, which is useful for workspaces that own multiple branded domains.

Sources: packages/cli/src/commands/domains.ts

dub domains

The command is interactive and treats cancellation as an intentional user action. If the prompt is canceled, it prints a warning, adds spacing, and exits with status zero through the process exit path. That means cancellation is not modeled as an API failure. The spinner is also stopped after domains are fetched so the prompt can own the terminal. Validation happens on the selected slug rather than on free-form typed input, but it still provides a guardrail against malformed values. After a successful selection, the saved configuration becomes part of later CLI state and can be inspected with the config command.

Sources: packages/cli/src/commands/domains.ts, packages/cli/src/commands/config.ts

The shorten command supports both direct invocation and an interactive prompt. If a destination URL is passed as the first argument, the command uses it immediately. If a key is not supplied, the command has a default value generated by the nanoid helper. If no URL is supplied, the command prompts for both the destination URL and short key, pre-filling the key prompt with a generated value. Before collecting or submitting link data, the command calls the configuration reader, so users are expected to authenticate before creating links.

Sources: packages/cli/src/commands/shorten.ts

dub shorten https://example.com launch
dub shorten https://example.com
dub shorten

Once the link data is available, the command starts a spinner labeled as creating a new short link and delegates creation to the link API helper. On success, it marks the spinner as successful and prints the generated short link in green. On failure inside the creation step, it fails the spinner, stops it, adds spacing, and rethrows so the shared error handler can render the final error. This nested error handling is important for user experience: API creation failures get an explicit failed creation message, while the broader command still follows the common CLI error path.

Sources: packages/cli/src/commands/shorten.ts

The links command is a read workflow for existing workspace links. It reads local configuration, creates a Dub client with the stored access token, and calls the client’s link listing method. The command accepts an optional search term and an optional limit. In the implementation, the limit is parsed as an integer and mapped to pageSize; if no limit is provided, it uses ten results. The search argument is passed through to the API request, so the command is useful both as a quick recent-links view and as a filtered lookup tool.

Sources: packages/cli/src/commands/links.ts

dub links
dub links --search launch
dub links --limit 25
dub links -s launch -l 25

The output is designed for terminal scanning rather than raw API inspection. Each returned link is converted into a row with short link, destination URL, click count, and a localized creation date. The date formatting includes month, day, hour, minute, and a twelve-hour clock, making the table suitable for quick human review. Because the command uses console.table, it is best treated as an operator-facing report, not as a stable machine-readable interface. Scripts that need structured link data should use the API or SDK directly rather than scraping this display.

Sources: packages/cli/src/commands/links.ts

Development and Production-like CLI Runs

For contributors working on the package, the README describes a local development loop. From the CLI package directory, run the development build in watch mode, then use a second terminal to invoke package scripts with the desired command. This separates compilation from command execution, which is helpful when iterating on command modules. The README also documents a help command invocation through the package script, allowing contributors to verify the generated Commander help output after changing command names, descriptions, arguments, or options.

Sources: packages/cli/README.md

cd packages/cli
pnpm dev
pnpm start login
pnpm start help

The README also includes a production-like setup for validating the globally linked executable. It instructs contributors to build the package, link it globally, verify the version with the binary, and then run commands through dub. The warning to uninstall a previously installed global dub-cli first matters because global package conflicts can make testing misleading. If the wrong executable is on the path, command changes in the repository may appear broken or absent even though the local build is correct.

Sources: packages/cli/README.md

cd packages/cli
pnpm build
npm link
dub -v
dub links

Compact Reference

WorkflowCommandKey behaviorSource
Authenticatedub loginOpens browser OAuth with link and domain scopes, then waits on a localhost callback.packages/cli/src/commands/login.ts
Inspect configdub configReads local configuration and prints colorized JSON.packages/cli/src/commands/config.ts
Select domaindub domainsFetches workspace domains, prompts for one, validates the slug, and saves it.packages/cli/src/commands/domains.ts
Create linkdub shorten [url] [key]Uses arguments or prompts, creates a link, and prints the generated short link.packages/cli/src/commands/shorten.ts
Search linksdub links -s <search> -l <limit>Lists links with optional search and page-size limit, then prints a table.packages/cli/src/commands/links.ts

Practical Sequencing and Next Steps

A sensible first-run sequence is to log in, inspect config, choose a domain, create a test short link, and then search for that link. This mirrors the dependencies in the code: authentication establishes the token, domain configuration stores a workspace preference, shortening creates a resource, and link listing confirms the result. If a command fails, check whether it is a setup failure or an API action failure. Configuration retrieval errors point back to login or local config state, while creation or listing errors are more likely related to API access, request data, or workspace permissions.

Sources: packages/cli/src/commands/login.ts, packages/cli/src/commands/config.ts, packages/cli/src/commands/domains.ts, packages/cli/src/commands/shorten.ts, packages/cli/src/commands/links.ts

For broader context, read the Links API pages when you need request and response details beyond the terminal workflows, the Domains API pages when you need domain registration or update operations not exposed by this CLI command set, and the CLI Reference page when you need the binary-level command catalog. The CLI is intentionally focused: it offers a fast path for authentication, domain choice, link creation, and link discovery, while the full dashboard and API remain the places for advanced attribution, conversion tracking, partner-program, and administrative workflows.