Introduction
What it is
cred is a command-line tool that stores encrypted secrets locally and pushes them to deployment platforms on demand.
β οΈ Status: Early Preview (v0.16.0)
cred is currently in active development. The on-disk format, CLI surface, and security model may change between minor versions. Do not rely on it as your sole secrets backup yet.
What it is not
- A hosted secrets manager
- A multi-user or multi-machine tool
- A replacement for HashiCorp Vault or AWS Secrets Manager
- A runtime secret injector for applications
Who is this for
- Solo developers managing secrets on a single machine
- Open-source maintainers who push secrets to deployment platforms
- Anyone who wants local-first secrets without running infrastructure
Why cred exists
Managing secrets in projects and deployment platforms is a mess and a chore.
cred solves this by giving you:
1. An Encrypted Vault per Project
Your secrets live inside .cred/vault.enc as an encrypted store with per-secret metadata (format, timestamps, description, source, version history).
2. Environment Namespacing
Organize secrets by deployment context:
cred env create prod
cred secret set DATABASE_URL "postgres://prod..." --env prod
cred push github --env prod
3. Version History & Rollback
Every secret update is tracked. Roll back to any of the last 10 versions:
cred secret history API_KEY
cred secret rollback API_KEY --version 0 --yes
4. Sources and Targets
cred distinguishes between sources (where credentials come from) and targets (where secrets are pushed to):
- Sources: Platforms that can programmatically generate credentials (e.g., Resend API keys)
- Targets: Platforms where you push secrets for deployment (e.g., GitHub Actions secrets)
5. Secure Key Storage
Your encryption key is stored in your OS credential store (Keychain, GNOME Keyring, Windows Credential Manager). Nothing sensitive is written to plaintext files.
Supported sources:
- Resend (API key generation)
Supported targets:
- GitHub (Actions secrets)
- Vercel (Environment variables)
- Fly.io (App secrets)
Installation
Homebrew (macOS)
brew tap edneedham/cred
brew install edneedham/cred/cred
Quick install (shell)
curl -fsSL https://raw.githubusercontent.com/edneedham/cred/main/scripts/install.sh | sh -s
Install with Cargo:
cargo install cred
Pre-built binaries
Download the latest release for your platform from GitHub Releases.
Available binary targets:
cred-vX.Y.Z-aarch64-apple-darwin- macOS Apple Siliconcred-vX.Y.Z-x86_64-apple-darwin- macOS Intelcred-vX.Y.Z-x86_64-unknown-linux-gnu- Linux x86_64cred-vX.Y.Z-x86_64-pc-windows-msvc.exe- Windows
Make the binary executable and move it to your PATH:
chmod +x cred-*
sudo mv cred-* /usr/local/bin/cred
Check installation:
cred --version
Getting Started
Get from zero to your first secret push in under 5 minutes.
1. Initialize your project
cred init
This creates .cred/vault.enc in your project and stores the encryption key in your OS credential store.
cred automatically detects targets from your project:
Initialized new cred project at .cred/
π Encryption key generated and stored in the System Credential Store
π Detected targets:
github: owner/repo
Run 'cred target set <target>' to authenticate each target.
2. Authenticate a target
cred target set github
Youβll be prompted for a fine-grained PAT with Actions secrets permission. The token is stored per-project, so each project can use different tokens (important for fine-grained PATs scoped to specific repos).
3. Store a secret
cred secret set DATABASE_URL "postgres://user:pass@localhost/db"
4. Push to GitHub
Preview first:
cred push github --dry-run
Then push:
cred push github
No --repo flag needed β cred uses the target binding saved during init.
Done! Your secret is now in GitHub Actions.
Working with Environments
Organize secrets by environment (dev, staging, prod):
# Create environments
cred env create staging
cred env create prod
# Set secrets in specific environments
cred secret set DATABASE_URL "postgres://prod..." --env prod
# Push prod secrets to GitHub
cred push github --env prod
See env command for more details.
Next steps:
- Commands Reference β all available commands
- Environments β organize secrets by environment
- Sources β generate credentials from APIs like Resend
- Security Model β how your secrets are protected
Migrating
Upgrading from v0.13.x to v0.14.0
v0.14.0 introduces first-class target scoping for secrets.
What Changed
- Secrets can now be scoped to specific targets via
cred secret set --targets ... cred push/cred prunerespect those scopes by default- Existing secrets are unscoped by default (no behavior change until you add scopes)
Recommended Migration
For projects where some targets are βfrontend onlyβ (e.g. Vercel), start scoping the relevant secrets:
# Public frontend variables (Vercel only)
cred secret set NEXT_PUBLIC_API_URL "https://..." --targets vercel
# Backend secrets (GitHub only)
cred secret set DATABASE_URL "postgres://..." --targets github
If you ever need to override scoping for a one-off push/prune, use --force.
Upgrading from v0.12.x to v0.13.0
v0.13.0 introduces per-project target tokens. Your existing vaults and secrets are unchanged, but target authentication needs to be re-configured.
What Changed
| Before (v0.12.x) | After (v0.13.0) |
|---|---|
| One global token per target | Per-project tokens |
cred target set stored globally | cred target set stores per-project |
--repo/--app flags often needed | Target bindings saved in project |
Migration Steps
In each of your cred projects:
cd your-project
# Re-authenticate targets (tokens now stored per-project)
cred target set github --token <your-fine-grained-pat>
# Verify target bindings were auto-detected or set them manually
cred target list
# If needed, bind targets manually
cred target bind github owner/repo
cred target bind fly my-app
Why This Change?
Modern fine-grained tokens (like GitHub PATs) are scoped to specific repos. A token for repo-a cannot access repo-b. Per-project token storage properly supports this security model.
Migrating Existing Secrets to cred
If you choose to migrate to cred instead of continuing with manual .env files youβll need the original values from wherever you stored them (password manager, .env files, etc.).
Migration Steps
1. Initialize cred:
cred init
2. Import your secrets:
From a .env file:
cred import .env
Or add individually:
cred secret set DATABASE_URL "postgres://..."
cred secret set API_KEY "sk-..."
Tip: Use environments to organize secrets by deployment context:
cred env create prod
cred import prod.env --env prod
3. Set up the GitHub target:
cred target set github
4. Push to GitHub:
Preview first:
cred push github --dry-run
Then push:
cred push github
Your existing workflows continue working unchanged β they reference secrets by name, and cred pushes to the same location.
Why Migrate?
| Before (manual) | After (cred) |
|---|---|
| Secrets in .env files or notes | Single encrypted vault |
| Copy-paste into GitHub UI | cred push github |
| No visibility into whatβs deployed | cred status shows everything |
| Hard to sync across repos | Push to multiple targets |
Concepts
cred is built around three core concepts that work together to manage your secrets.
Vault
The vault is your local encrypted secrets store. Each project has its own vault at .cred/vault.enc containing all your secrets with metadata like format, timestamps, and descriptions.
Learn more about the Vault β
Sources
Sources are platforms that can programmatically generate credentials. Instead of manually creating API keys, you can have cred generate them for you with the appropriate permissions.
Currently supported:
- Resend β Email API key generation
Targets
Targets are platforms where you push secrets for deployment. cred uploads your vault secrets to these platforms so your workflows can access them directly.
Currently supported:
- GitHub β Actions secrets
- Vercel β Environment variables
- Fly.io β App secrets
How They Work Together
βββββββββββββββ generate βββββββββββββββ push βββββββββββββββ
β Source β ββββββββββββββββΊ β Vault β βββββββββββββββΊ β Target β
β (Resend) β β (encrypted) β β (GitHub) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β²
β manual set
β
βββββββββββββββ
β You β
βββββββββββββββ
- Sources generate credentials and store them in your vault
- You can also manually add secrets to the vault
- Targets receive secrets when you push from the vault
Sources
Sources are platforms that can programmatically generate credentials. Unlike targets (which only receive secrets), sources create new API keys on demand.
Why Use Sources?
Instead of manually creating API keys in a web dashboard and copy-pasting them, sources let you:
- Generate keys directly from the command line
- Automatically store them in your vault with proper metadata
- Track which keys came from which source
- Revoke all generated keys at once when needed
Adding a Source
Add your master API key:
cred source add resend --token "$RESEND_API_KEY"
Or interactively (will prompt for token):
cred source add resend
The master token is stored securely in your OS credential store (keyring), not in plaintext files.
Generating Credentials
Generate a new API key from the source:
cred source generate resend RESEND_EMAIL_KEY --permission sending_access -d "Email service key"
This creates a new API key via Resendβs API and stores it in your vault with source: resend metadata.
Managing Source Keys
List API keys at the source:
cred source keys resend
Delete a generated key (removes from source AND local vault):
cred source delete resend RESEND_EMAIL_KEY --yes
List configured sources:
cred source list
Revoking a Source
Revoke source authentication (deletes all generated keys and removes master key):
cred source revoke resend --yes
This will:
- Delete all API keys generated from this source at Resend
- Remove them from the local vault
- Remove the stored master key
Resend
Resend is an email API service. cred can generate API keys with specific permission levels.
Permission Levels
| Permission | Description |
|---|---|
full_access | Can create, delete, get, and update any resource |
sending_access | Can only send emails (recommended for most use cases) |
Example
# Add your master key (needs full_access to create other keys)
cred source add resend
# Generate a restricted key for your app
cred source generate resend EMAIL_API_KEY --permission sending_access
# Push to GitHub Actions
cred push github
Why Sources Use Master Keys
Sources authenticate with a master API key that has permission to create additional keys. The generated keys can have narrower scopes (e.g., sending_access only), following the principle of least privilege.
Your application never sees the master key β it only gets the restricted key you generated.
Targets
Targets are platforms where you push secrets for deployment. cred uploads your vault secrets to these platforms so your workflows can access them directly.
How It Works
Your machine Target platform Your workflow
βββββββββββ ββββββββββββββββ ββββββββββββ
β cred βββpushββββββββΊβ GitHub βββββββββββ workflow β
β (vault) β β Secrets β reads β β
βββββββββββ ββββββββββββββββ ββββββββββββ
- You run
cred push githubon your dev machine - cred uploads secrets to GitHub Actions
- Your workflows read secrets directly from GitHub β no cred involved
Per-Project Tokens
As of v0.13.0, target tokens are stored per-project, not globally. This properly supports fine-grained tokens (like GitHub PATs scoped to specific repos).
Each project has its own:
- Target bindings β the identifier for each target (repo, app, project ID)
- Target tokens β authentication credentials stored in OS keyring
This means:
- Project A can use a GitHub PAT scoped to
owner/repo-a - Project B can use a different PAT scoped to
owner/repo-b - No token conflicts or accidental cross-project access
Target Bindings
Target bindings are saved in .cred/project.toml during cred init (auto-detected) or via cred target bind:
# .cred/project.toml
[targets]
github = "owner/repo"
fly = "my-app"
vercel = "prj_xxxxx"
Bind a target manually:
cred target bind github owner/repo
cred target bind fly my-app
cred target bind vercel prj_xxxxx
Once bound, you donβt need --repo, --app, or --project flags when pushing.
Target-Scoped Secrets (v0.14.0+)
Secrets can optionally be scoped to specific targets. This is useful when, for example, your Vercel target is βfrontend onlyβ and you want to avoid pushing backend secrets there.
- Unscoped secrets (default): eligible for all targets
- Scoped secrets: only eligible for the listed targets
Set scopes when writing a secret:
cred secret set NEXT_PUBLIC_API_URL "https://..." --targets vercel
cred secret set DATABASE_URL "postgres://..." --targets github,fly
cred push <target> and cred prune <target> respect these scopes by default. Use --force to override.
Adding a Target
Authenticate a deployment target (must be inside a cred project):
cred target set github
You will be securely prompted for a token. The token is stored in your OS credential store, scoped to this project.
Managing Targets
List configured targets for this project:
cred target list
Output shows binding and authentication status:
Project Targets:
β github = owner/repo
β fly = my-app
Run 'cred target set <target>' to authenticate.
Revoke a target:
cred target revoke github --yes
GitHub
GitHub Actions secrets are the primary target for cred. Secrets you push become available to your workflows.
Setup
- Create a fine-grained Personal Access Token at github.com/settings/tokens
- Select only the repository you want to manage
- Grant only the Actions secrets permission (read and write)
- Add the token to cred:
cred target set github
Pushing Secrets
# Push all secrets
cred push github
# Push specific secrets
cred push github DATABASE_URL API_KEY
cred automatically detects your repository from git metadata. If youβre not in a git repository, specify it explicitly:
cred push github --repo owner/repo
Using Secrets in Workflows
Once pushed, secrets are available in your GitHub Actions:
jobs:
deploy:
runs-on: ubuntu-latest
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
steps:
- run: echo "Secret is available"
Vercel
Push environment variables to Vercel projects. Secrets you push become available to your deployments.
Setup
- Create an Access Token at vercel.com/account/tokens
- Grant Full Account scope (required for environment variable management)
- Add the token to cred:
cred target set vercel
Linking Your Project
cred auto-detects your Vercel project from .vercel/project.json (created by vercel link). If you havenβt linked:
vercel link
Or specify the project ID explicitly:
cred push vercel --project prj_xxxxxxxxxxxxx
Environment Mapping
cred environments map to Vercel targets:
| cred env | Vercel target |
|---|---|
prod | production |
default | development |
| others | preview |
# Push to Vercel production
cred push vercel --env prod
# Push to Vercel development (default)
cred push vercel
Using Secrets in Deployments
Once pushed, environment variables are automatically available in your Vercel deployments:
// Next.js example
const apiKey = process.env.API_KEY;
Fly.io
Push secrets to Fly.io apps. Secrets you push become available to your deployed applications.
Setup
- Create a Personal Access Token at fly.io/user/personal_access_tokens
- Add the token to cred:
cred target set fly
Linking Your App
cred auto-detects your Fly.io app from fly.toml (created by fly launch). If you havenβt launched:
fly launch
Or specify the app name explicitly:
cred push fly --app my-app-name
Pushing Secrets
# Push all secrets
cred push fly
# Push specific secrets
cred push fly DATABASE_URL API_KEY
# Push to a specific app
cred push fly --app my-app-name
Applying Secrets
After pushing secrets, Fly.io requires a deployment to apply them:
fly deploy
# or
fly secrets deploy
Using Secrets in Your App
Once deployed, secrets are available as environment variables:
// Node.js example
const apiKey = process.env.API_KEY;
# Python example
import os
api_key = os.environ.get("API_KEY")
Why Targets Use Simple Tokens
Targets need minimal permissions β just enough to write secrets. This follows the principle of least privilege.
Unlike sources (which need elevated permissions to generate new credentials), targets only need write access to a specific resource (e.g., GitHub Actions secrets for one repository, Vercel environment variables for one project).
Vault
The vault is your local encrypted secrets store. Each cred project has its own vault containing all secrets with rich metadata, organized by environment.
Structure
When you run cred init, cred creates:
.cred/
βββ project.toml # Project metadata
βββ vault.enc # Encrypted secrets
Global configuration lives at:
~/.config/cred/global.toml
Environments
Secrets are organized into environments (e.g., default, staging, prod). This allows you to manage different configurations for different deployment contexts.
# List environments
cred env list
# Create an environment
cred env create prod
# Set a secret in an environment
cred secret set DATABASE_URL "postgres://..." --env prod
By default, secrets are stored in the default environment.
See cred env for more details.
Secret Metadata
Each secret in the vault includes:
| Field | Description |
|---|---|
key | The secret name (e.g., DATABASE_URL) |
value | The encrypted secret value |
format | Content format (raw, json, pem, etc.) |
created_at | When the secret was first added |
updated_at | When the secret was last modified |
description | Optional human-readable description |
source | Where it came from (manual or a source name) |
history | Up to 10 previous versions (for rollback) |
Secret Formats
cred auto-detects the format of your secrets:
| Format | Detection | Example |
|---|---|---|
pem | Starts with -----BEGIN | Certificates, private keys |
json | Valid JSON object or array | {"key": "value"} |
base64 | Single-line base64 content | SGVsbG8gV29ybGQ= |
multiline | Contains newlines | Multi-line text |
raw | Everything else (default) | super-secret-value |
You can also specify format explicitly:
cred secret set MY_KEY "value" --format json
Viewing the Vault
List all secrets:
cred secret list
Output:
Vault content:
API_KEY = ***** (OpenAI production key)
DATABASE_URL = *****
JWT_SECRET = ***** [modified]
Get a specific secret:
cred secret get JWT_SECRET
With full metadata (JSON):
cred secret get JWT_SECRET --json
{
"data": {
"key": "JWT_SECRET",
"value": "super-secret",
"format": "raw",
"created_at": "2025-12-11T12:00:00Z",
"updated_at": "2025-12-11T12:00:00Z",
"description": null
}
}
Version History
cred automatically tracks up to 10 previous versions of each secret. View history and rollback:
# View version history
cred secret history DATABASE_URL
# Rollback to previous version (0 = most recent)
cred secret rollback DATABASE_URL --version 0 --yes
See cred secret history for more details.
Hub-and-Spoke Status
For a complete overview of your project:
cred status
Vault: 5 secrets (2 environments)
Environment: default
RESEND_API_KEY [resend]
DATABASE_URL [manual]
Environment: prod
DATABASE_URL [manual]
JWT_SECRET [manual]
API_KEY [manual]
Sources: resend β
Targets: github β
Encryption
The vault is encrypted at rest using ChaCha20-Poly1305. The encryption key is generated on cred init and stored in your OS credential store (Keychain, GNOME Keyring, etc.). See Security Model for details.
Best Practices
- Add
.cred/to.gitignoreβ Never commit your vault - Use descriptions β Document what each secret is for
- Use environments β Separate dev/staging/prod secrets
- Keep backups β Export periodically with
cred export - Use sources when possible β Generated keys have better audit trails
- Review history before rollback β Use
cred secret historyfirst
Commands
Complete reference for all cred commands.
Project Management
| Command | Description |
|---|---|
cred init | Initialize a new cred project |
cred status | Show vault, sources, and targets overview |
cred doctor | Check project health |
Secrets
| Command | Description |
|---|---|
cred secret set | Add or update a secret |
cred secret get | Retrieve a secret value |
cred secret list | List all secrets |
cred secret remove | Delete a secret from vault |
cred secret describe | Update a secretβs description |
cred secret history | View version history for a secret |
cred secret rollback | Restore a previous version |
cred import | Import from .env file |
cred export | Export to .env file |
Environments
| Command | Description |
|---|---|
cred env list | List all environments |
cred env create | Create a new environment |
cred env delete | Delete an environment and its secrets |
Deployment
| Command | Description |
|---|---|
cred push | Push secrets to a target |
cred prune | Delete secrets from a target |
Sources
| Command | Description |
|---|---|
cred source add | Add a credential source |
cred source generate | Generate a new credential |
cred source keys | List keys at the source |
cred source delete | Delete a generated key |
cred source list | List configured sources |
cred source revoke | Remove source and all its keys |
Targets
| Command | Description |
|---|---|
cred target set | Authenticate with a target |
cred target bind | Bind target identifier to project |
cred target list | List configured targets |
cred target revoke | Remove a targetβs token |
Configuration
| Command | Description |
|---|---|
cred config list | View all configuration |
cred config get | Get a config value |
cred config set | Set a config value |
cred config unset | Remove a config value |
Global Flags
All commands support these flags:
| Flag | Description |
|---|---|
--json | Machine-readable JSON output |
--non-interactive | Fail instead of prompting for input |
--dry-run | Preview changes without applying them |
--help | Show help for any command |
init
Initialize a cred project.
Usage
Initialize a new cred project in the current directory:
cred init
This creates:
.cred/
βββ project.toml # Project configuration (includes target bindings)
βββ vault.enc # Encrypted secrets vault
Run this once per project, typically at the repository root.
What Happens
- Creates the
.cred/directory - Generates a random 32-byte encryption key
- Stores the key in your OS credential store (Keychain, GNOME Keyring, etc.)
- Creates an empty encrypted vault
- Adds
.cred/to.gitignore - Auto-detects target bindings from your project
Auto-Detection
cred automatically detects and saves target bindings during init:
| Target | Detection Source |
|---|---|
| GitHub | Git remote (git@github.com:owner/repo.git) |
| Fly.io | fly.toml (app = "my-app") |
| Vercel | .vercel/project.json (projectId) |
Example output:
Initialized new cred project at .cred/
π Encryption key generated and stored in the System Credential Store
π Detected targets:
github: owner/repo
fly: my-app
Run 'cred target set <target>' to authenticate each target.
These bindings are saved in .cred/project.toml:
name = "my-project"
version = "0.1.0"
id = "..."
git_repo = "owner/repo"
[targets]
github = "owner/repo"
fly = "my-app"
Project Name
The project name defaults to the directory name where you run cred init.
Next Steps
After init, authenticate your targets:
cred target set github # Prompts for fine-grained PAT
cred target set fly # Prompts for Fly.io token
Then you can push without specifying --repo or --app:
cred push github # Uses saved binding
cred push fly # Uses saved binding
Important Notes
- cred is single-machine only β the vault and encryption key stay on your dev machine
- Use
cred pushto deploy secrets to platforms like GitHub Actions - Your CI/CD reads secrets from the target platform directly, not from cred
- Target tokens are stored per-project to support fine-grained tokens
See Security Model for more details.
target
Manage deployment targets for this project.
Overview
Target commands manage:
- Authentication β tokens for each target platform
- Bindings β identifiers (repo, app, project ID) for each target
Both tokens and bindings are stored per-project, enabling fine-grained tokens scoped to specific resources.
target set
Authenticate with a target platform.
cred target set <target>
Examples
# Authenticate with GitHub (prompts for token)
cred target set github
# Provide token directly (for automation)
cred target set github --token ghp_xxxxx
Supported Targets
| Target | Token Type |
|---|---|
github | Fine-grained PAT with Actions secrets permission |
vercel | Access Token from vercel.com/account/tokens |
fly | Personal Access Token from fly.io/user/personal_access_tokens |
Notes
- Must be inside a cred project (
cred initfirst) - Tokens are stored in OS credential store, scoped to this project
- Each project can have different tokens for the same target
target setalso ensures a binding exists (repo/app/projectId):- If a binding is already present in
.cred/project.toml, it is kept. - Otherwise cred tries to auto-detect from project files.
- If detection fails, cred prompts you for the identifier.
- With
--non-interactive, cred errors and tells you to runcred target bind <target> <identifier>.
- If a binding is already present in
target bind
Bind a target identifier to this project.
cred target bind <target> <identifier>
Examples
# Bind GitHub repo
cred target bind github owner/repo
# Bind Fly.io app
cred target bind fly my-app-name
# Bind Vercel project
cred target bind vercel prj_xxxxxxxxxxxxx
When to Use
- When auto-detection during
cred initdidnβt find your target - When you want to override the auto-detected binding
- When setting up a new target after init
Bindings are saved in .cred/project.toml:
[targets]
github = "owner/repo"
fly = "my-app-name"
target list
List targets configured for this project.
cred target list
Output
Project Targets:
β github = owner/repo
β fly = my-app
Run 'cred target set <target>' to authenticate.
- β = authenticated (token stored)
- β = binding exists but not authenticated
JSON Output
cred target list --json
{
"api_version": "1",
"status": "ok",
"data": {
"targets": [
{
"name": "github",
"identifier": "owner/repo",
"authenticated": true
},
{ "name": "fly", "identifier": "my-app", "authenticated": false }
]
}
}
target revoke
Remove a targetβs authentication token.
cred target revoke <target> --yes
Examples
# Revoke GitHub token
cred target revoke github --yes
# Dry-run to preview
cred target revoke github --dry-run
Notes
- Requires
--yesflag (destructive operation) - Only removes the token; the binding remains in project.toml
- For some targets (GitHub), attempts remote token revocation first
Workflow Example
# Initialize project (auto-detects GitHub from git remote)
cred init
# Authenticate GitHub with fine-grained PAT
cred target set github
# Add a Fly.io app binding
cred target bind fly my-app
# Authenticate Fly.io
cred target set fly
# List all targets
cred target list
# Push to GitHub (no --repo needed)
cred push github
# Push to Fly.io (no --app needed)
cred push fly
config
Manage global cred configuration.
Configuration is stored at ~/.config/cred/global.toml. Sensitive values (tokens) are stored in your OS keyring, not in this file.
list
View all configuration:
cred config list
get
Get a specific value:
cred config get preferences.default_target
set
Set a configuration value:
cred config set preferences.default_target github
unset
Remove a configuration value:
cred config unset preferences.default_target
Available Settings
| Key | Description |
|---|---|
preferences.default_target | Default target for push/prune commands |
doctor
Check project health and diagnose issues in machine readable JSON:
cred doctor
Output:
{
"api_version": "1",
"data": {
"cred_installed": true,
"global_config": true,
"keychain_access": true,
"project_detected": false,
"ready_for_push": false,
"targets": [],
"vault_accessible": false,
"version": "0.4.0"
},
"status": "ok"
}
This verifies:
- Vault file exists and is readable
- Configuration is valid
- Keyring access works
- Sources and targets are reachable
status
Show a hub-and-spoke overview of your project:
cred status
Output:
Vault: 5 secrets (2 environments)
Environment: default
RESEND_API_KEY [resend]
DATABASE_URL [manual]
Environment: prod
DATABASE_URL [manual]
JWT_SECRET [manual]
API_KEY [manual]
Sources: resend β
Targets: github β
Git: edneedham/cred
This shows:
- Total secrets and environment count
- Secrets grouped by environment
- Each secretβs source (manual or generated)
- Configured sources and targets
- Git repository (if detected)
JSON Output
For machine-readable output:
cred status --json
secret
Manage secrets in your local vault.
set
Add or update a secret:
cred secret set DATABASE_URL "postgres://user:pass@localhost:5432/db"
Target Scopes (v0.14.0+)
Scope a secret to specific deployment targets. This helps prevent accidentally pushing backend-only secrets to frontend targets.
Unscoped secrets (default) are eligible for all targets.
# Only push this to Vercel
cred secret set NEXT_PUBLIC_API_URL "https://..." --targets vercel
# Push this to GitHub and Fly only
cred secret set DATABASE_URL "postgres://..." --targets github,fly
Clear scopes (make unscoped again):
cred secret set DATABASE_URL "postgres://..." --clear-targets
With a description:
cred secret set API_KEY "sk-xxx" --description "OpenAI production key"
cred secret set CERT_PEM "-----BEGIN..." -d "TLS certificate"
In a specific environment:
cred secret set DATABASE_URL "postgres://prod..." --env prod
Format Detection
cred auto-detects the format of your secrets:
| Format | Detection | Example |
|---|---|---|
pem | Starts with -----BEGIN | Certificates, keys |
json | Valid JSON object/array | {"key": "value"} |
base64 | Single-line base64 | SGVsbG8gV29ybGQ= |
multiline | Contains newlines | Multi-line text |
raw | Default | Single-line text |
Override auto-detection:
cred secret set MY_KEY "value" --format json
get
Retrieve a secret value:
cred secret get JWT_SECRET
From a specific environment:
cred secret get JWT_SECRET --env prod
With full metadata:
cred secret get JWT_SECRET --json
{
"data": {
"key": "JWT_SECRET",
"value": "super-secret",
"format": "raw",
"created_at": "2025-12-11T12:00:00Z",
"updated_at": "2025-12-11T12:00:00Z",
"description": null
}
}
list
List all secrets in the vault (shows all environments by default):
cred secret list
Output:
Vault content (3 environments, 4 secrets):
[default] (1 secrets)
DEFAULT_KEY = *****
[production] (2 secrets)
PROD_KEY = *****
API_KEY = ***** (OpenAI production key)
[staging] (1 secrets)
STAGING_KEY = *****
List secrets in a specific environment:
cred secret list --env prod
Output:
Vault content (env: production):
PROD_KEY = *****
API_KEY = ***** (OpenAI production key)
Descriptions are shown inline when present.
remove
Delete a secret from the local vault:
cred secret remove JWT_SECRET --yes
From a specific environment:
cred secret remove JWT_SECRET --env prod --yes
Output:
β Removed 'JWT_SECRET' from local vault (3 days old)
Note: This only removes from the local vault. To delete from a target, use
cred prune.
describe
Update a secretβs description:
cred secret describe API_KEY "Updated: rotating quarterly"
Clear a description:
cred secret describe API_KEY
history
View the version history of a secret:
cred secret history DATABASE_URL
Output:
History for 'DATABASE_URL' in env 'default':
[current] 2025-01-03 14:30:00 (manual)
[0] 2025-01-02 10:15:00 (manual)
[1] 2025-01-01 09:00:00 (manual)
Use 'cred secret rollback DATABASE_URL --version <N>' to restore
From a specific environment:
cred secret history DATABASE_URL --env prod
cred keeps up to 10 previous versions of each secret.
rollback
Restore a secret to a previous version:
cred secret rollback DATABASE_URL --version 0 --yes
The --version flag specifies which historical version to restore (0 = most recent previous value).
From a specific environment:
cred secret rollback DATABASE_URL --version 0 --env prod --yes
Preview before rolling back:
cred secret rollback DATABASE_URL --version 0 --dry-run
Note: Rollback is a destructive operation and requires
--yesto confirm.
generate
Generate a cryptographic key pair locally using OpenSSL.
Basic Usage
Generate an RSA 2048-bit key pair:
cred secret generate API_KEY --type pem
This creates two secrets:
API_KEY_PRIVATEβ The RSA private key (PKCS#1 format)API_KEY_PUBLICβ The RSA public key
Requirements
OpenSSL must be installed and available in your PATH.
Install OpenSSL:
- macOS:
brew install openssl - Ubuntu/Debian:
sudo apt install openssl - Fedora:
sudo dnf install openssl
Environment-Specific Generation
Generate keys in a specific environment:
cred secret generate JWT_SIGNING_KEY --type pem --env production
Creates JWT_SIGNING_KEY_PRIVATE and JWT_SIGNING_KEY_PUBLIC in the production environment.
Overwriting Existing Keys
By default, generate refuses to overwrite existing keys. Use --force to overwrite:
cred secret generate API_KEY --type pem --force
Dry Run
Preview what would be generated:
cred secret generate API_KEY --type pem --dry-run
Output:
(dry-run) Would generate RSA 2048-bit PEM key pair 'API_KEY' in env 'default'
Key Metadata
Generated keys include:
- Format:
pem(automatically detected) - Source:
generated - Description: βRSA 2048-bit key pair (generated by cred)β
Pushing Generated Keys
Push both keys to a target:
cred push github
Or push only specific keys:
cred push github API_KEY_PRIVATE API_KEY_PUBLIC
Supported Key Types
| Type | Description | Format |
|---|---|---|
pem | RSA 2048-bit key pair | PKCS#1 PEM |
import
Import KEY=VALUE pairs from a .env file:
cred import .env
Import to a specific environment:
cred import prod.env --env prod
Existing keys are skipped by default to keep imports non-destructive.
Overwrite existing keys:
cred import .env --overwrite
Preview without writing:
cred import .env --dry-run
export
Write vault contents to a .env file:
cred export .env.backup
Export from a specific environment:
cred export prod.env --env prod
Keys are sorted alphabetically. Existing files are preserved unless forced:
cred export .env --force
Preview:
cred export .env --dry-run
env
Manage environments for organizing secrets. Environments allow you to separate secrets for different contexts (e.g., dev, staging, prod).
Overview
By default, all secrets are stored in the default environment. You can create additional environments to isolate secrets for different deployment contexts.
list
List all environments:
cred env list
Output:
Environments:
default (3 secrets)
staging (2 secrets)
prod (5 secrets)
create
Create a new environment:
cred env create staging
Output:
β Created environment 'staging'
delete
Delete an environment and all its secrets:
cred env delete staging --yes
Output:
β Deleted environment 'staging' (2 secrets removed)
β οΈ This is a destructive operation β requires --yes to confirm.
Using Environments
Most secret commands accept an --env flag:
# Set a secret in the prod environment
cred secret set DATABASE_URL "postgres://prod..." --env prod
# Get a secret from staging
cred secret get API_KEY --env staging
# List secrets in a specific environment
cred secret list --env prod
# Push prod secrets to GitHub
cred push github --env prod
# Export prod secrets to a file
cred export prod.env --env prod
Environment Strategy
Common patterns:
| Environment | Purpose |
|---|---|
default | Development/local secrets |
staging | Pre-production testing |
prod | Production secrets |
Migration from v0.5.x
If youβre upgrading from a version without environments, your existing secrets are automatically migrated to the default environment. No action required.
import
Import secrets from a .env file into the local vault.
Usage
cred import <path> [OPTIONS]
Arguments
| Argument | Description |
|---|---|
<path> | Path to the .env file to import |
Options
| Option | Description |
|---|---|
--overwrite | Overwrite existing keys instead of skipping |
-e, --env <name> | Target environment (auto-detected from cred exports) |
Behavior
Plain .env Files
When importing a standard .env file:
# Import to default environment
cred import .env
# Import to a specific environment
cred import .env --env prod
Secrets are imported as plain key-value pairs without metadata.
Cred Export Files
When importing a file created by cred export:
# Import preserving environments and metadata
cred import vault.env
Cred automatically detects export files by their header and:
- Recreates environment structure from the file
- Restores secret metadata (descriptions, timestamps)
- Creates any environments that donβt exist
To force all secrets into a single environment:
# Override: import all secrets to staging environment
cred import vault.env --env staging
Examples
# Import from .env, skip existing keys
cred import .env
# Import and overwrite existing keys
cred import .env --overwrite
# Import to production environment
cred import prod.env --env prod
# Import a cred export file (auto-detects format)
cred import teammate-vault.env
# Preview what would be imported
cred import .env --dry-run
Output
β Imported .env (added 5, overwritten 0, skipped 2).
For cred export files with multiple environments:
β Imported vault.env (created 2 env(s)) (added 10, overwritten 0, skipped 0).
export
Export vault secrets to a .env file.
Usage
cred export <path> [OPTIONS]
Arguments
| Argument | Description |
|---|---|
<path> | Path to write the exported file |
Options
| Option | Description |
|---|---|
--force | Overwrite the output file if it exists |
-e, --env <name> | Export only this environment (exports full vault if omitted) |
--plain | Plain .env format (no metadata, requires --env) |
Export Formats
Full Vault Export (Default)
By default, cred export creates a rich export file containing all environments with metadata:
cred export vault.env
Output format:
# cred-export v1
# exported: 2025-01-07T10:30:00Z
#
# To import: cred import <this-file>
# [environment: default]
# [API_KEY]
# description: Development API key
# created: 2025-01-01T00:00:00Z
API_KEY=sk-dev-xxx
# [DATABASE_URL]
DATABASE_URL=postgres://localhost/dev
# [environment: prod]
# [API_KEY]
# description: Production API key
# created: 2025-01-05T00:00:00Z
API_KEY=sk-prod-xxx
This format:
- Preserves all environments
- Includes secret metadata (descriptions, timestamps)
- Can be imported by
cred importto recreate the full vault
Single Environment Export
Export just one environment with metadata:
cred export prod.env --env prod
Output format:
# cred-export v1
# environment: prod
# exported: 2025-01-07T10:30:00Z
#
# To import: cred import <this-file>
# [API_KEY]
# description: Production API key
API_KEY=sk-prod-xxx
Plain Export
Export as a standard .env file without metadata:
cred export .env --env default --plain
Output format:
API_KEY=sk-dev-xxx
DATABASE_URL=postgres://localhost/dev
Use this when you need a standard .env file for tools that donβt understand cred comments.
Examples
# Export full vault with metadata
cred export vault.env
# Export only production environment
cred export prod.env --env prod
# Export as plain .env (no metadata)
cred export .env --env default --plain
# Overwrite existing file
cred export vault.env --force
# Preview what would be exported
cred export vault.env --dry-run
Output
β Exported 10 secrets (3 environment(s)) to vault.env.
For single environment:
β Exported 5 secrets (env 'prod') to prod.env.
Use Cases
Sharing Secrets with Teammates
Export your vault and share the file securely:
cred export team-vault.env
# Transfer file securely (encrypted email, secure share, etc.)
Teammate imports:
cred import team-vault.env
Backup
Create a backup of your entire vault:
cred export backup-$(date +%Y%m%d).env
Integration with Other Tools
When you need a standard .env for other tools:
cred export .env --env default --plain
push
Push secrets from your vault to a target platform.
Basic Usage
Push all secrets to GitHub:
cred push github
Push all secrets to Vercel:
cred push vercel
Push all secrets to Fly.io:
cred push fly
No --repo, --app, or --project flags needed β cred uses the target bindings saved in your project.
Push specific secrets only:
cred push github DATABASE_URL JWT_SECRET
Dry Run
Preview what will change before pushing:
cred push github --dry-run
Preview specific keys:
cred push github DATABASE_URL JWT_SECRET --dry-run
Nothing is uploaded when --dry-run is used.
Environment-Specific Push
Push secrets from a specific environment:
cred push github --env prod
This pushes only secrets from the prod environment.
Options
| Flag | Description |
|---|---|
--env <name> | Push from specific environment |
--repo <owner/repo> | Explicit repository (GitHub) |
--project <id> | Explicit project ID (Vercel) |
--app <name> | Explicit app name (Fly.io) |
--force | Ignore per-secret target scopes |
--dry-run | Preview changes without pushing |
--json | Machine-readable output |
--non-interactive | Fail instead of prompting |
Target Scopes (v0.14.0+)
If a secret is scoped to specific targets, cred push <target> will:
- Include unscoped secrets
- Include secrets scoped to
<target> - Skip (or refuse, if explicitly requested) secrets scoped to other targets
If you explicitly request a key that isnβt scoped to the target, cred refuses by default. Use --force to override.
Target Resolution
cred resolves target identifiers in this order:
- CLI flag (
--repo,--app,--project) β highest priority - Project binding (saved in
.cred/project.toml) - Auto-detection (git remote, fly.toml, etc.) β fallback
GitHub
Target binding is auto-detected from git remote during cred init, or set manually:
cred target bind github owner/repo
Override with CLI flag if needed:
cred push github --repo different/repo
Vercel
Target binding is auto-detected from .vercel/project.json during cred init, or set manually:
cred target bind vercel prj_xxxxxxxxxxxxx
Override with CLI flag if needed:
cred push vercel --project prj_other
Fly.io
Target binding is auto-detected from fly.toml during cred init, or set manually:
cred target bind fly my-app-name
Override with CLI flag if needed:
cred push fly --app different-app
Note: After pushing secrets to Fly.io, run fly deploy or fly secrets deploy to apply changes.
Incremental Updates
cred tracks which secrets have changed since the last push. Only modified secrets are updated remotely, making pushes efficient.
Workflow Example
# Add a secret
cred secret set DATABASE_URL "postgres://..."
# Preview the push
cred push github --dry-run
# Push when ready
cred push github
Updating Secrets
To update a secret:
# Update locally
cred secret set JWT_SECRET "new-secret-value"
# Preview changes
cred push github --dry-run
# Apply
cred push github
Only the changed secret will be updated at the target.
prune
Delete secrets from a target platform. This is a remote-only operation β it does not affect your local vault.
Basic Usage
Remove a specific key from a target:
cred prune github JWT_SECRET --yes
Remove multiple keys:
cred prune github JWT_SECRET OLD_API_KEY --yes
Dry Run
Preview what will be deleted:
cred prune github JWT_SECRET --dry-run
Prune All
Remove all known keys from a target:
cred prune github --all --yes
This removes all secrets that cred has pushed to this target.
Environment-Specific Prune
Prune secrets from a specific environment:
cred prune github OLD_KEY --env prod --yes
Options
| Flag | Description |
|---|---|
--env <name> | Prune from specific environment |
--repo <owner/repo> | Explicit repository (GitHub) |
--project <id> | Explicit project ID (Vercel) |
--app <name> | Explicit app name (Fly.io) |
--force | Ignore per-secret target scopes |
--dry-run | Preview without deleting |
--yes | Confirm destructive operation |
--all | Prune all known secrets |
--json | Machine-readable output |
Safety
β οΈ Destructive operations require --yes unless using --dry-run.
This prevents accidental deletion of production secrets.
Local vs Remote
| Operation | Command |
|---|---|
| Delete from vault (local) | cred secret remove KEY --yes |
| Delete from target (remote) | cred prune github KEY --yes |
| Delete from both | Run both commands |
Workflow Example
Remove a secret completely:
# Remove from GitHub first
cred prune github OLD_SECRET --yes
# Then remove from local vault
cred secret remove OLD_SECRET --yes
Security Model
cred is designed with security as a core concern. This page explains how your secrets are protected.
Encryption at Rest
Your vault (.cred/vault.enc) is encrypted using ChaCha20-Poly1305, a modern authenticated encryption algorithm. This provides both confidentiality and integrity protection.
Key Storage
The encryption key is:
- Randomly generated on
cred init(32 bytes) - Stored in your OS credential store
- Never written to disk as plaintext
| OS | Backend |
|---|---|
| macOS | Keychain |
| Linux | Secret Service (GNOME Keyring, KWallet) |
| Windows | Credential Manager |
Token Storage
Source and target tokens (API keys, PATs) are also stored in your OS credential store.
Tokens are never written to plaintext files like ~/.config/cred/global.toml.
What cred Protects Against
- Accidental exposure β Secrets arenβt in plaintext files that could be committed
- Disk compromise β Vault is encrypted at rest
- Clipboard history β Interactive prompts for sensitive input
- Overprivileged keys β Sources generate restricted-scope credentials
What cred Does NOT Protect Against
- Compromised machine β If an attacker has access to your running system, they can access your keyring
- Memory attacks β Secrets exist in memory during operations
- Malicious targets β cred trusts the platforms you push to
Safe Inspection
Use --dry-run to preview any operation before it executes:
cred push github --dry-run
cred prune github --all --dry-run
This is especially important for destructive operations.
Best Practices
1. Never Commit Your Vault
The .cred/ directory is added to .gitignore on init. Never commit it:
# Verify it's ignored
cat .gitignore | grep .cred
2. Use Least Privilege
- For sources: Use master keys only for generation, deploy restricted keys
- For targets: Create fine-grained PATs with minimal permissions
3. Keep Backups
Export your vault periodically:
cred export secrets-backup.env
Store backups securely (encrypted, offline).
4. Audit Your Secrets
Review whatβs in your vault:
cred status
cred secret list
Remove secrets you no longer need.
Threat Model
cred is designed for:
- Solo developers managing secrets on a single machine
- Open-source maintainers who push secrets to deployment platforms
- Projects that donβt require multi-user access control
It is not designed for:
- Team environments with multiple users
- Multi-machine environments (cred is single-machine only)
- Compliance-heavy industries (healthcare, finance) without additional controls
- Scenarios requiring audit trails or approval workflows