The Embeddable CLI (embed) is a command-line tool that serves as a user-friendly wrapper around the Embeddable API. Embeddable is a developer toolkit for building fast, fully-custom analytics experiences directly into applications.
Embeddable provides:
- Code-based data model definitions for developers
- No-code dashboard assembly for business users
- Native web component embedding with built-in security
- Performance optimization through advanced caching
The CLI abstracts away direct API communication, allowing users to:
- Manage database connections without manual API calls
- Create and configure environments
- Generate security tokens for dashboard embedding
- List available embeddables
- Setup wizard for guided onboarding
- TypeScript - Type-safe development with NodeNext module resolution
- Citty - Modern CLI framework with command routing and better TypeScript support
- @clack/prompts - Beautiful interactive prompts with better UX than standard prompts
- Chalk v5 - Colored terminal output (ESM)
- Ora v8 - Loading spinners (ESM)
- cli-table3 - Table formatting for data display
- Bun - For building native binaries
The project has been fully migrated to ES Modules (ESM):
- Uses
"type": "module"in package.json - All imports use
.jsextensions for local TypeScript files - TypeScript configured with
NodeNextmodule resolution - Latest versions of all dependencies (no CommonJS constraints)
- Removed
node-fetchdependency (use nativefetchAPI)
The CLI communicates with Embeddable's REST API:
- Base URLs:
- US:
https://api.us.embeddable.com/api/v1 - EU:
https://api.eu.embeddable.com/api/v1 - Dev:
https://api.dev.embeddable.com/api/v1
- US:
- Authentication: Bearer token in Authorization header
- Content-Type: application/json
-
Database Connections
- No direct database communication
- CLI sends connection configs to Embeddable API
- Supports PostgreSQL, MySQL, BigQuery, Snowflake, Redshift
- Connection testing via API endpoint
-
Environments
- Map data sources to database connections
- Support multiple deployment stages (prod, staging, etc.)
- Single-tenant database security
-
Security Tokens
- Generate JWT tokens for dashboard embedding
- Include user context and row-level security
- Configurable expiration times
-
Setup Wizard
- Interactive onboarding flow for new users
- Guides through API configuration, database connection, and environment setup
- Optional token generation at the end
- Automatically runs on first-time use when no config exists
The CLI supports both modes for flexibility:
Interactive Mode (default):
embed database connect
# User is prompted for each fieldNon-Interactive Mode:
embed database connect --json '{"name":"prod-db",...}'
embed database connect --file connection.json- Stored in
~/.embeddable/config.json - Contains API key, region, and default environment
- Secure credential storage on user's machine
The CLI provides:
- Friendly error messages (not raw API errors)
- Suggestions for common issues
- Debug mode with
--debugflag - Proper exit codes for scripting
- Use Bun to compile self-contained executables
- Platform-specific binaries: Linux, macOS (ARM64), Windows
- No runtime dependencies required
- Homebrew (macOS): Custom tap repository
- Scoop (Windows): Manifest for easy installation
- npm: For Node.js users who prefer npm global install
pnpm install # Install dependencies
pnpm build # Compile TypeScript
pnpm typecheck # Type checking
pnpm lint # Lintingnode dist/cli.js --help
pnpm dev -- --help # Using tsx for developmentnpm run build:all # Build for all platformsThe CLI uses citty's defineCommand pattern for modular command organization:
// Main CLI entry point
const main = defineCommand({
meta: { name: 'embed', version, description: '...' },
subCommands: {
init: createInitCommand(),
auth: createAuthCommand(),
database: createDatabaseCommand(),
env: createEnvironmentCommand(),
list: createListCommand(),
token: createTokenCommand(),
setup: createSetupCommand(),
version: createVersionCommand(),
config: createConfigCommand(),
}
});Each command is created using factory functions that return citty command definitions:
export function createTokenCommand() {
return defineCommand({
meta: { name: 'token', description: '...' },
args: {
embeddableId: { type: 'positional', required: false },
env: { type: 'string', alias: 'e' }
},
async run({ args }) { /* implementation */ }
});
}When users run embed without any configuration:
- CLI detects missing config file
- Automatically starts the init process
- Prompts user to optionally run the setup wizard
- Shows regular help if user declines setup
Key learnings about @clack/prompts:
-
Select Prompts: Must include
hintfield for options to display properlyconst selected = await p.select({ message: 'Select an embeddable:', options: items.map(item => ({ value: item.id, label: item.name, hint: item.id // Important: helps with rendering })) });
-
Text Input with Validation:
const input = await p.text({ message: 'Enter workspace ID:', placeholder: 'e.g., 512cc2a8-9b8c-4ba1-8ca7-5799d8d9a66b', validate: (value) => { if (!uuidRegex.test(value)) { return 'Please enter a valid UUID'; } } });
-
Spinners: Use for async operations
const spinner = p.spinner(); spinner.start('Loading...'); // async work spinner.stop();
-
API Key Security
- Never log or display full API keys
- Show only last 4 characters when displaying
- Always validate API key on login
-
User Feedback
- Use spinners for long operations
- Provide clear success/error messages
- Show progress for multi-step operations
-
Defaults and Convenience
- Remember user's default environment
- Suggest sensible defaults (e.g., port 5432 for PostgreSQL)
- Allow both interactive and scriptable usage
-
Additional Database Types
- Currently supports major databases
- BigQuery requires service account JSON
- Other databases need JSON config input
-
Enhanced Features
- Bulk operations support
- Configuration import/export
- Team collaboration features
-
Testing
- Unit tests for API client
- Integration tests with mock API
- CLI command tests
- Environments use
datasourcesarray format (not object) - Each datasource entry has
data_sourceandconnectionfields - Example:
[{ "data_source": "main_db", "connection": "postgres-prod" }]
- The
userfield expects a string, not an object - Example:
"user": "user123"(not"user": { "id": "user123" }) - Security context is passed as a JSON object for row-level security
- Validation endpoint returns 200 with empty body for valid keys
- Check
response.okrather than parsing response content
-
ESM Module Errors
- All dependencies now use ESM (fixed in latest version)
- Node.js v18+ required for proper ESM support
- Use
.jsextensions in TypeScript imports
-
API Authentication
- Validate API key on init/login
- Provide clear error for invalid credentials
- Some endpoints require different auth (workspace API)
-
@clack/prompts Display Issues
- Select prompts need
hintfield to display options properly - Use
p.intro()for better visual organization
- Select prompts need
-
Platform-Specific Builds
- Bun required for native binary compilation
- Fallback to Node.js execution if binaries unavailable
- Token command now prompts for environment selection if none provided
- Displays HTML embedding example with the generated token
- Shows direct link to documentation for advanced options
- README.md restructured as concise overview with navigation
- Created comprehensive docs/ folder with 9 focused guides:
- getting-started.md - First steps and setup wizard
- installation.md - Platform-specific installation
- commands.md - Complete command reference
- configuration.md - Config management and regions
- databases.md - Database types and setup
- environments.md - Environment management
- tokens.md - Security token generation
- examples.md - Real-world workflows
- troubleshooting.md - Common issues and solutions
- Automatic version checking with proper release note filtering
- Homebrew update integration (requires manual formula update currently)
- Clear update instructions based on installation method
-
GitHub Repository Setup:
- Main repository:
embeddable-hq/embeddable-cli - Homebrew tap repository:
embeddable-hq/homebrew-embeddable - Secrets needed:
NPM_TOKEN- For publishing to npm (not yet configured)HOMEBREW_TAP_TOKEN- GitHub PAT with repo access to tap repository
- Main repository:
-
Scoop Bucket (Optional):
- Repository:
embeddable-hq/scoop-bucket
- Repository:
-
Use the release script:
./scripts/release.sh
This will:
- Update version in package.json
- Create a git tag
- Push to GitHub
-
GitHub Actions will automatically:
- Create a GitHub release
- Build binaries for all platforms
- Publish to npm as
@embeddable/cli - Update Homebrew formula
-
Manual steps (if needed):
- Update Scoop manifest
- Update documentation
- Automatic checks: CLI checks for updates every 24 hours
- Manual check:
embed version --check - Update methods:
- Homebrew:
brew upgrade embed - npm:
npm install -g @embeddable/cli@latest - Binary: Download from GitHub releases
- Homebrew:
The formula is located at homebrew-tap/Formula/embed.rb and is automatically updated by GitHub Actions on new releases.
This CLI makes Embeddable's powerful analytics platform accessible through simple commands, reducing the learning curve and speeding up integration for developers.