A command-line interface for managing Cloudflare Workers KV storage. Written in Rust with async/await support.
📖 Documentation: For detailed guides, see the docs/ folder
- CRUD Operations - Get, put, and delete key-value pairs
- Batch Operations - Delete multiple keys at once
- List & Pagination - Query keys with cursor-based pagination
- TTL Support - Set expiration time for keys
- Metadata - Store additional metadata with keys
- Multiple Output Formats - JSON, YAML, or plain text
- Configuration Management - Store credentials securely
- Debug Logging - Optional verbose logging for troubleshooting
- Rust 1.70 or later
- Cargo
git clone <repository-url>
cd cfkv-cli
cargo build --releaseThe binary will be available at target/release/cfkv (or cfkv.exe on Windows).
For easy access from anywhere, install the binary:
cargo install --path crates/cfkvThis installs cfkv to ~/.cargo/bin/ (which should be in your PATH if you have Rust installed).
If you only built the release binary, you can either:
-
Use the full path:
/<PROJECT_PATH>/cfkv-cli/target/release/cfkv --help
-
Add to PATH temporarily (in current shell):
export PATH="/path/to/cfkv-cli/target/release:$PATH" cfkv --help
-
Add to PATH permanently (edit
~/.zshrc,~/.bashrc, or~/.bash_profile):export PATH="/path/to/cfkv-cli/target/release:$PATH"
Then reload:
source ~/.zshrc -
Create a symlink:
sudo ln -s /path/to/cfkv-cli/target/release/cfkv /usr/local/bin/cfkv
Before setting up cfkv, you'll need three pieces of information from Cloudflare:
- Go to https://dash.cloudflare.com/
- Click your profile icon → My Profile
- Go to API Tokens tab
- Click Create Token (use "Edit zone DNS" template or create custom)
- Copy the token value
- Go to https://dash.cloudflare.com/
- The URL shows:
https://dash.cloudflare.com/YOUR_ACCOUNT_ID - Copy the ID from the URL
Or via API:
curl -X GET "https://api.cloudflare.com/client/v4/accounts" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json"- Go to https://dash.cloudflare.com/
- Click Workers & Pages → KV
- Find your KV namespace and click it
- Copy the Namespace ID
Or check your wrangler.toml:
kv_namespaces = [
{ binding = "MY_KV", id = "abc123xyz789", preview_id = "test123" }
]Once you have all three values, configure cfkv:
cfkv config set-token <YOUR_API_TOKEN>
cfkv config set-account <YOUR_ACCOUNT_ID>
cfkv config set-namespace <YOUR_NAMESPACE_ID>The configuration is stored at:
- macOS/Linux:
~/.config/cfkv/config.json - Windows:
%APPDATA%\cfkv\config.json
cfkv config showcfkv config resetInstead of storing in config file, use environment variables:
export CF_API_TOKEN="your-api-token"
export CF_ACCOUNT_ID="your-account-id"
export CF_NAMESPACE_ID="your-namespace-id"
cfkv config showFor comprehensive storage management documentation, see docs/STORAGE_MANAGEMENT.md.
cfkv supports managing multiple named storage configurations. This allows you to easily switch between different Cloudflare accounts, namespaces, or environments (production, staging, development, etc.) without having to reconfigure credentials each time.
Add a new named storage with your credentials:
# Add a production storage
cfkv storage add prod \
--account-id <ACCOUNT_ID> \
--namespace-id <NAMESPACE_ID> \
--api-token <API_TOKEN>
# Add a development storage
cfkv storage add dev \
--account-id <DEV_ACCOUNT_ID> \
--namespace-id <DEV_NAMESPACE_ID> \
--api-token <DEV_API_TOKEN>
# Add a staging storage
cfkv storage add staging \
--account-id <STAGING_ACCOUNT_ID> \
--namespace-id <STAGING_NAMESPACE_ID> \
--api-token <STAGING_API_TOKEN>View all configured storages and see which one is active (marked with *):
cfkv storage list
# Output:
# Available storages:
#
# * prod (account: abc123, namespace: ns456)
# dev (account: def456, namespace: ns789)
# staging (account: ghi789, namespace: ns012)With JSON output:
cfkv --format json storage listDisplay details about the currently active storage:
cfkv storage current
# Output:
# Current storage: prod
# Account ID: abc123
# Namespace ID: ns456Switch to a different storage. All subsequent commands will use the new storage:
# Switch to development storage
cfkv storage switch dev
# Now all commands use the dev storage
cfkv get mykey # Gets from dev namespace
cfkv put mykey --value "test" # Puts to dev namespaceShow details about a specific storage:
# Show current storage (default)
cfkv storage show
# Show details of a specific storage
cfkv storage show --name prodRename a storage configuration:
cfkv storage rename prod productionRemove a storage configuration:
cfkv storage remove stagingIf the removed storage was active, cfkv will automatically switch to another available storage.
Storage configurations are saved in your config file:
{
"storages": {
"prod": {
"name": "prod",
"account_id": "abc123...",
"namespace_id": "ns456...",
"api_token": "token789..."
},
"dev": {
"name": "dev",
"account_id": "def456...",
"namespace_id": "ns789...",
"api_token": "token012..."
}
},
"active_storage": "prod"
}If you're upgrading from an older version of cfkv that used the legacy single-storage configuration format, your existing configuration will be automatically migrated to the new format on first use:
- Your existing credentials (account_id, namespace_id, api_token) will be migrated to a storage named
default - The
defaultstorage will be set as active - All subsequent commands will work with the migrated storage
No manual action is required for the migration.
cfkv get mykey
cfkv get mykey --format json --pretty # Pretty-printed JSON output# With a string value
cfkv put mykey --value "my value"
# With a file
cfkv put mykey --file /path/to/file
# With TTL (time to live in seconds)
cfkv put mykey --value "my value" --ttl 3600
# With metadata
cfkv put mykey --value "my value" --metadata '{"type": "text"}'cfkv delete mykey# List all keys (default limit: 1000)
cfkv list
# List with custom limit
cfkv list --limit 100
# Pagination using cursor
cfkv list --cursor "next_cursor_value"cfkv batch delete key1 key2 key3The blog plugin allows you to publish and manage markdown blog posts in Cloudflare KV.
cfkv blog publish path/to/blog-post.mdBlog posts must be markdown files with YAML frontmatter:
---
slug: my-blog-post
title: My Blog Post Title
description: A short description of the post
author: Author Name
date: 2025-01-15
cover_image: blog/image.jpg
tags:
- rust
- webdev
---
# Your markdown content here
This is the body of your blog post.Required fields: slug, title, description, author, date
slug: Post URL identifier (lowercase, numbers, hyphens only)date: Publication date in YYYY-MM-DD formatcover_image: Optional image pathtags: Optional list of tags
cfkv blog list
cfkv blog list --format json
cfkv blog list --format yamlcfkv blog delete my-blog-post--config <PATH> Path to config file (default: ~/.config/cfkv/config.json)
--account-id <ID> Cloudflare account ID (overrides config)
--namespace-id <ID> KV namespace ID (overrides config)
--api-token <TOKEN> API token (overrides config)
--format <FORMAT> Output format: text, json, yaml (default: text)
--debug Enable debug logging
--pretty Pretty-print JSON output
--value <VALUE> String value to store
--file <PATH> File to store (reads file contents)
--ttl <SECONDS> Time to live in seconds
--metadata <JSON> JSON metadata object
--limit <N> Number of keys to return (default: 1000)
--cursor <CURSOR> Pagination cursor
--metadata Include metadata in results
$ cfkv get mykey
my value$ cfkv get mykey --format json --pretty
{
"key": "mykey",
"value": "my value"
}$ cfkv get mykey --format yaml
key: mykey
value: my valuecf-kv-cli/ # Root workspace
├── Cargo.toml # Workspace configuration (no code here)
├── Cargo.lock
├── README.md
├── .gitignore
└── crates/
├── cloudflare-kv/ # Core KV client library
│ ├── Cargo.toml
│ └── src/
│ ├── lib.rs # Library exports
│ ├── client.rs # HTTP client
│ ├── auth.rs # Authentication
│ ├── types.rs # Type definitions
│ ├── error.rs # Error types
│ └── batch.rs # Batch operations
├── cfkv/ # Main CLI application
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # Entry point
│ ├── cli.rs # CLI command definitions
│ ├── config.rs # Configuration management
│ └── formatter.rs # Output formatting
├── cfkv-blog/ # Blog plugin crate
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── cfkv-config/ # Config utilities plugin crate
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── cfkv-cache/ # Cache utilities plugin crate
├── Cargo.toml
└── src/
└── lib.rs
This project uses a Rust workspace pattern:
- Root
Cargo.toml: Defines workspace members and shared dependencies - cloudflare-kv: Core library that can be published separately or used by other projects
- cfkv: Binary that uses the core library to provide CLI functionality
- cfkv-*: Plugin crates that extend the core library for specific use cases
All crates share:
- Same version number
- Shared dependency versions
- Single
Cargo.lockfile
cargo build # Debug build
cargo build --release # Optimized release buildcargo testcargo run -p cfkv -- get mykey
cargo run -p cfkv -- put mykey --value "test"cargo run -p cfkv -- --debug get mykey- Batch import from JSON/YAML files
- Batch export to files
- Namespace management commands
- Interactive REPL mode
- Configuration profiles for multiple accounts
- Key filtering and search
- Performance metrics and statistics
Key dependencies (from Cargo.toml):
tokio- Async runtimereqwest- HTTP clientclap- CLI argument parsingserde/serde_json/serde_yaml- Serializationthiserror- Error handlingtracing/tracing-subscriber- Logging
MIT
Contributions are welcome! Please feel free to submit issues or pull requests.
For issues or questions:
- Check the Cloudflare KV documentation
- Open an issue on the repository
- Review the debug output with
--debugflag