Thanks for your interest in ByteTable — a free, local-first desktop database client for SQLite, MySQL, PostgreSQL, SQL Server, Redis, DynamoDB, MongoDB and Cassandra. Contributions of all kinds are welcome: bug reports, fixes, features, docs, and design feedback.
By contributing you agree that your work is licensed under the project's Apache License 2.0.
- Report a bug — open an issue with steps to reproduce, what you expected, what happened, your OS, and the engine/version involved.
- Suggest a feature — open an issue describing the use case before sending a large PR, so we can agree on the approach first.
- Send a pull request — fixes, features, tests, or docs (see below).
- Core: Tauri 2 + Rust (engine adapters, commands, secrets).
- Renderer: React 19 + TypeScript + Vite, Zustand for state.
- Engines: rusqlite (SQLite), sqlx (MySQL/PostgreSQL), tiberius (SQL Server), the
rediscrate (Redis), aws-sdk-dynamodb (DynamoDB), mongodb (MongoDB), scylla (Cassandra).
- Node + pnpm (renderer).
- Rust toolchain (rustup) —
makewill install it viaensure-cargoif missing. - Docker (optional) — only to run the real MySQL/PostgreSQL/SQL Server/Redis/DynamoDB/MongoDB/Cassandra test databases.
- See the README "Prerequisites" section for platform-specific system libraries.
make install # install renderer dependencies (pnpm)
make hooks # install the git pre-commit hook (one-time)
make dev # run the app with hot reload (Tauri + Vite)To exercise the app against real databases:
make db-up # start Postgres/MySQL/SQL Server/Redis/DynamoDB/MongoDB/Cassandra in Docker + seed them
make db-down # stop and wipe themThe seed data lives in test-fixtures/seed/ (*.sql per engine, plus
seed-redis.sh for a rich Redis keyspace).
macOS keychain prompts in dev: dev builds are ad-hoc signed, so the OS may re-ask for keychain access. Run
make dev-certonce to sign dev builds with a stable identity (thenmake runis prompt-free after one "Always Allow").
make hooks installs a husky pre-commit
hook (also installed automatically by pnpm install via the prepare script).
On every commit it runs lint-staged,
which applies prettier --write to your staged files only (*.{ts,tsx,js,jsx,json,css,md,html})
and re-stages the result — so commits stay Prettier-clean and the CI
format:check step won't fail. It does not touch unstaged files or run the
slower full-repo make fmt.
Bypass it for a one-off (e.g. a WIP commit) with git commit --no-verify.
src/ Renderer (React/TS), one folder per feature
features/<feature>/ components / state (Zustand) / api (typed invoke wrappers)
shared/ design tokens, UI primitives, wire types
src-tauri/ Rust core
src/engines/ engine adapters (sqlite, postgres, mysql, mssql, redis, dynamo, mongo, cassandra, ssh tunnel)
src/features/<feature>/ domain / application / ports / infrastructure / commands
src/shared/ error type, engine + key-value port traits
test-fixtures/ docker-compose + seeds + sample SQLite
docs/ design specs
ByteTable follows a vertical-slice + clean-architecture layout: each feature
owns its domain, application, and adapter code, and never reaches across into
another feature's internals. Per-engine SQL/commands live only under
src-tauri/src/engines/* — feature/application code stays engine-agnostic.
- Branch off
dev— all work starts fromdev, and all PRs are raised againstdev, notmain.mainis the release branch; never commit or open PRs directly against it. - Name the branch by its purpose (see the patterns below).
- Keep it focused — one logical change per PR. Match the style and patterns of the surrounding code; read a nearby file before adding a new one.
- Add tests for backend logic. SQLite is fully unit-testable in-process; MySQL/PostgreSQL/SQL Server/Redis paths have unit tests for SQL generation and gated integration tests against the Docker databases.
- Run all the checks (below) and make sure they pass.
- Open a PR into
devwith a clear description of what changed and why. Link any related issue.
Prefix the branch by the kind of work, followed by a short kebab-case summary:
| Kind | Prefix | Example |
|---|---|---|
| Feature | feat/ |
feature/carousel-lens-zoom |
| Refactor | refactor/ |
refactor/filter-panel-state |
| Bug fix | bugfix/ |
bugfix/ctrl-f-toggle |
| Hotfix | hotfix/ |
hotfix/keychain-crash |
- feat/ — new functionality.
- refactor/ — restructuring with no behavior change.
- bugfix/ — fixes branched off and merged back into
dev. - hotfix/ — urgent production fixes; branched off
main, then merged into bothmainanddevso the fix isn't lost on the next release.
- One feature per branch. A
feature/branch contains only that feature — no drive-by bug fixes, refactors, or unrelated tweaks. Spun off a fix while working? Put it on its ownbugfix/branch and PR it separately. - Mixing concerns makes a PR hard to review and impossible to revert cleanly.
We keep dev and main a linear history — no merge commits from
long-running branches.
-
Rebase, don't merge. Pull upstream changes with
git pull --rebase origin dev(orgit rebase dev) rather than mergingdevinto your branch. Resolve conflicts on your commits. -
Squash before you open the PR. If your branch has grown a lot of WIP / "fix typo" / "address review" commits, squash them into a small set of meaningful commits first:
git rebase -i dev # mark noise commits as `squash`/`fixup` git push --force-with-leaseAim for one commit per logical step (often just one for a small feature).
-
Never force-push a shared branch (
dev,main) — only your own feature branch.
Run the whole suite:
make test # Rust tests + TS typecheck
make lint # ESLint + clippy + rustfmt/prettier checks
make fmt # auto-format (prettier + rustfmt) — run before pushingOr directly, the way CI runs them:
# Frontend
pnpm typecheck
pnpm lint
pnpm format:check # or `pnpm format` to fix
pnpm build
# Backend (from src-tauri/)
cargo test --all-features
cargo clippy --all-features -- -D warnings
cargo fmt --check # or `cargo fmt` to fixClippy runs with -D warnings, so warnings fail the build — fix them rather
than allowing them.
- No unrelated churn — don't reformat or refactor code you aren't changing.
- Comments earn their place — explain why, not what; match the density of the file you're editing.
- Errors are human — surface engine/validation failures as clear, actionable
sentences (the
AppError/ §5 pattern), never raw driver text. - Secrets — database passwords and SSH secrets go to the OS keychain, never into the connection registry or any committed file.
- Keep adapters thin and engine-specific code where it belongs — SQL and
driver calls live under
src-tauri/src/engines/*only.
Write clear, present-tense messages explaining the change ("Fix Redis key grid alignment", not "fixes"). Reference an issue number when one applies.
ByteTable is licensed under the Apache License 2.0. All contributions are accepted under the same license.