This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Beekeeper Studio is a cross-platform SQL editor and database manager built with Electron, Vue.js 2, and TypeScript. It supports 15+ databases and offers both community (GPLv3) and paid editions.
apps/studio/- Main Electron applicationapps/ui-kit/- Reusable UI components library (@beekeeperstudio/ui-kit)apps/sqltools/- Currently unused workspace
- Frontend: Vue.js 2.7, TypeScript, Vuex for state management
- Desktop: Electron 31.7.3
- Build: ESBuild (main process), Vite (renderer process)
- Testing: Vitest for unit tests; integration tests are mid-migration from Jest to Vitest (see
apps/studio/tests/VITEST_MIGRATION.md); Playwright for e2e. All new tests must be Vitest specs inapps/studio/tests/vitest/— CI fails PRs that add specs to the legacy jest tree (tests/integration/; e2e is exempt). - Styling: SCSS with multiple themes
All entrypoints are listed under src-commercial/entrypoints
- Main Process:
src-commercial/entrypoints/main.ts(Electron main) - Renderer Process:
src-commercial/entrypoints/renderer.ts&src/App.vue(Vue application) - Preload Script:
src-commercial/entrypoints/preload.ts - *Utility Process:
src-commercial/entrypoints/utility.ts
- ConnectionInterface - Database connection screen
- CoreInterface - Main database interaction interface (when connected)
Package Manager: This project uses Yarn (not npm).
# Development
yarn bks:dev # Start development server (builds lib + starts electron)
yarn electron:serve # Alias for bks:dev
# Building
yarn bks:build # Build complete app (lib + electron)
yarn electron:build # Alias for bks:build
yarn lib:build # Build UI kit library only
yarn lib:dev # Start UI kit in development/watch mode
# Testing
yarn test:unit # Unit tests (Vitest, tests/vitest/unit) + ui-kit tests
yarn test:integration # Integration tests
yarn test:e2e # End-to-end tests with Playwright
yarn test:ci # CI-specific test configuration
yarn test:codemirror # CodeMirror-specific tests
yarn vitest:integration # Vitest integration tests (tests/vitest/integration)
yarn vitest:ci # Vitest integration tests minus docker-DB specs
# Linting
yarn all:lint # Lint all workspaces# Development
yarn electron:serve # Start development with hot reload
yarn dev:esbuild # Watch main process (ESBuild)
yarn dev:vite # Watch renderer process (Vite)
# Building
yarn build # Build both main and renderer processes
yarn build:esbuild # Build main process only
yarn build:vite # Build renderer process only
yarn electron:build # Full production build with electron-builder
# Test Build (Agents - use this to test the build, also good for CI)
yarn run electron:build --linux AppImage # Create Linux AppImage for testing
# Testing
yarn test:unit # Unit tests
yarn test:integration # Integration tests
yarn test:e2e # E2E tests
yarn lint # ESLintcomponents/ # Vue components organized by feature
├── common/ # Shared/reusable components
├── connection/ # Database connection forms
├── editor/ # Query editor components
├── export/ # Data export functionality
├── sidebar/ # Sidebar navigation components
└── ...
lib/ # Core business logic
├── db/ # Database clients and connection logic
├── editor/ # Text editor functionality (CodeMirror)
├── export/ # Data export functionality
├── cloud/ # Cloud/workspace features
└── ...
background/ # Electron main process code
common/ # Shared utilities and models
store/ # Vuex store modules
migration/ # Database migration scripts
assets/ # Styles, fonts, images
- Supports 15+ database types through unified client interface
- Database-specific clients in
src/lib/db/ - Connection pooling and SSH tunneling support
- TypeORM used for app's internal SQLite database
- Community features: GPLv3 license
- Paid features: Commercial EULA (code in
src-commercial/) - Both editions share the same codebase
- Extensible architecture for third-party plugins
- Plugin manager with install/update capabilities
- Plugin code in
src/services/plugin/
- ESBuild:
apps/studio/esbuild.mjs(main process build) - Vite:
apps/studio/vite.config.mjs(renderer process build) - TypeScript:
apps/studio/tsconfig.json - Jest:
apps/studio/jest.integration.config.js(legacy integration tree only, plus specialized configs extending it) - Vitest:
apps/studio/vitest.config.mjsfamily +vitest.shared.mjs(runs everything underapps/studio/tests/vitest/) - Electron Builder:
apps/studio/electron-builder-config.js
Always run tests from the appropriate directory:
- From root:
yarn test:unit,yarn test:integration,yarn test:e2e - From apps/studio:
yarn test:unit,yarn test:integration,yarn test:e2e
Test files are organized in apps/studio/tests/:
vitest/unit/- Unit tests (Vitest — put new unit tests here)vitest/integration/- Integration tests (Vitest — put new integration tests here)integration/- Legacy integration tests still on Jest (migrate, don't add)e2e/- End-to-end tests with Playwright
- Setup:
yarn installfrom root - Start development:
yarn bks:dev(from root) oryarn electron:serve(from apps/studio) - Run tests:
yarn test:unitbefore committing - Build:
yarn bks:buildfor production build
User-facing strings (button labels, tooltips, alerts, helper text, form hints) should be written as neutral statements, not first-person plural narration.
- Don't use "we", "we'll", "we found", "we couldn't", "we didn't". Don't address the app as if it's a person reporting back.
- Prefer terse statements about state or behaviour:
Resolved /path/to/key,No ssh-agent found,Falls back to User from ~/.ssh/config. - Don't anthropomorphise:
The agent will be queriedis fine,we'll ask the agentis not. - This applies to copy, not to code comments — internal comments may use "we" if it improves clarity.
Examples:
| Avoid | Prefer |
|---|---|
| "We found your ssh-agent socket: /tmp/agent.123" | "ssh-agent socket: /tmp/agent.123" |
| "We couldn't find an ssh config at /home/u/.ssh/config" | "No ssh config at /home/u/.ssh/config" |
| "If blank, we use User from ~/.ssh/config" | "If blank, falls back to User from ~/.ssh/config" |
| "We'll resolve HostName from your config" | "Resolves HostName from the matching entry" |
"@" -> "./src"
"@commercial" -> "./src-commercial"
"@shared" -> "./src/shared"
"assets" -> "./src/assets"
"@bksLogger" -> resolved per-build:
- esbuild main+preload → "./src/lib/log/mainLogger"
- esbuild utility → "./src/lib/log/utilityLogger"
- vite renderer → "./src/lib/log/rendererLogger"
- jest → "./src/lib/log/mainLogger"
- tsc / IDE → "./src/lib/log/bksLogger.d.ts" (ambient declaration; no runtime file)The app supports 15+ databases including PostgreSQL, MySQL, SQLite, SQL Server, Oracle, BigQuery, MongoDB, and more. Database-specific connection logic is in src/components/connection/ with corresponding client implementations in src/lib/db/.
The docs site (docs/, built by MkDocs from mkdocs.yml) builds in strict mode: any
MkDocs warning fails mkdocs build, the pull request check (.github/workflows/docs-check.yml)
and the deploy. Run pip install -r requirements.txt && mkdocs build --strict before pushing
docs changes.
- Link to other docs pages with relative
.mdpaths (../purchasing/license-types.md,manifest.md#pluginviewtype), never a bare path (../purchasing/license-types) or an old/docs/...URL. MkDocs validates the file and anchor and rewrites the link to a URL. - Site-root paths such as
/assets/images/foo.pngare resolved againstdocs/and validated. - Full
https://docs.beekeeperstudio.io/...URLs are only for content reused outside the site: the supported-databases table indocs/includes/, which is copied into the README files.bin/mkdocs_hooks/check_site_links.pychecks that those pages and anchors exist. - In-page anchors are the lowercased, hyphenated heading text (
## Multi-Table Exportis#multi-table-export). Translated pages have translated anchors; give a heading an explicit id with## Heading { #stable-id }when a link must work across languages.
The documentation site (docs/) uses MkDocs Material with the mkdocs-static-i18n plugin for multi-language support. See mkdocs.yml for the list of 10 target languages.
Translations use suffix-based naming:
- English (default):
filename.md - Spanish:
filename.es.md - Portuguese (Brazil):
filename.pt-BR.md - Other languages:
filename.{locale}.md
Translation files live alongside the original English files in the same directory.
- Copy the English file as a starting point
- Keep the same frontmatter structure (title, summary, icons, etc.) but translate the values
- Translate all content including:
- Frontmatter
titleandsummary - All body text and headings
- Alt text for images
- Admonition titles (e.g.,
!!! note "Translated Title")
- Frontmatter
- Do NOT translate:
- File paths and URLs
- Code blocks (unless comments need translation)
- Technical terms that are commonly used in English (e.g., "plugin", "SQL")
- Brand names (e.g., "Beekeeper Studio", "GitHub")
Add nav_translations in mkdocs.yml under each language locale to translate menu items:
- locale: es
name: Espanol
nav_translations:
Introduction: Introduccion
Features: Caracteristicas- Add the locale to
mkdocs.ymlunderplugins > i18n > languages - Include
site_name,site_description, andnav_translations - Create
.{locale}.mdfiles for each page indocs/ - Test with
mkdocs servefrom thestudio/directory
English is the primary language. To find all files needing translation for a new language:
- Scan
docs/recursively for all.mdfiles - Exclude files that already have a locale suffix (e.g.,
.es.md,.de.md) - For each English file found, create the corresponding
.{locale}.mdtranslation
Example: If you find docs/user_guide/security.md, create docs/user_guide/security.es.md for Spanish.
The main README.md has translations in the repo root using the pattern README-{locale}.md or README.{locale}.md:
README.md- English (primary)README-es.md- SpanishREADME.pt-br.md- Portuguese (Brazil)
When adding a new README translation:
- Create
README-{locale}.mdin the repo root - Add a link to it in the translation line at the top of
README.md
The first line of README.md links to all translations using the format:
🌐 [ES](README-es.md) | [PT-BR](README.pt-br.md)