docs/development/driver-dependencies.md
Some database drivers depend on binary files that can't ship inside the app (e.g. Oracle Instant Client). The driver-deps framework auto-downloads those files on demand, shows the user a license + details modal, and writes the install path back into a user setting so the existing driver flow picks it up.
The integration is a single shared UserSetting key:
oracleInstantClient) at connect time.SettingsInput to the same key. That
binding is what surfaces the auto-download button next to the field.The settingKey is the only contract between provider and driver —
nothing else is shared. If a driver already reads its path from a
user setting, adding auto-download to it is purely additive: no
driver-side or form changes are needed.
This page explains how to register a new dependency. Adding one is intentionally small: write a provider class, then add one line to the default registry.
apps/studio/src/services/driverDeps/
├── DriverDepFileManager.ts # download + extract + on-disk layout
├── DriverDepManager.ts # orchestrates installs / lookups
├── DriverDepRegistry.ts # in-memory registry of providers
├── index.ts # default registry (add your provider here)
├── providers/
│ └── OracleInstantClientProvider.ts
└── types.ts # DriverDepProvider, DriverRequirement, ...
Create apps/studio/src/services/driverDeps/providers/MyDriverProvider.ts.
A provider is self-describing — it declares its requirement metadata, the
connection types it applies to, and resolves the platform-specific
artifacts at runtime.
import {
DriverDepProvider,
DriverDepProviderInfo,
DriverRequirement,
} from "../types";
export const MY_DRIVER_REQUIREMENT_ID = "my-driver-files";
export default class MyDriverProvider implements DriverDepProvider {
readonly requirement: DriverRequirement = {
id: MY_DRIVER_REQUIREMENT_ID,
name: "My Driver Files",
// The UserSetting key the install path is written to. The
// SettingsInput component bound to this key auto-renders the
// download button — no form changes required.
// The integration contract. The driver reads its path from this
// user setting; the manager writes the install path here after
// download. The connection form's SettingsInput must use the
// same key.
settingKey: "myDriverFiles",
required: false,
};
// Connection types where this dep is offered (matches DB client `connectionType`).
readonly connectionTypes = ["mydriver"];
async resolve(): Promise<DriverDepProviderInfo> {
return {
requirementId: this.requirement.id,
version: "1.2.3",
artifacts: [
{
platform: "linux",
arch: "x64",
url: "https://example.com/my-driver-1.2.3-linux-x64.zip",
fileName: "my-driver-1.2.3-linux-x64.zip",
},
// ...mac, windows
],
licenseName: "My Driver License 1.0",
licenseUrl: "https://example.com/license",
documentationUrl: "https://example.com/docs",
// Optional: directory inside the archive to expose as the install
// path. Omit to auto-detect the first top-level extracted dir.
extractedDirName: "my-driver-1.2.3",
restartRequired: true,
notes: [
{
platforms: ["linux"],
text: "Requires glibc 2.x or later.",
},
],
};
}
}
A few rules worth noting:
requirement.settingKey must match the key on the SettingsInput
used by the connection form. That binding is what makes the
auto-download button appear next to the field.artifacts covers platform ∈ {linux, mac, windows} and arch ∈
{x64, arm64}. If a user's platform is missing, the install fails
with a clear error and the manual download URL is offered.extractedDirName is omitted, the file manager uses the first
top-level directory in the extracted archive. Set it explicitly when
the archive layout is stable.Open apps/studio/src/services/driverDeps/index.ts and add an instance
of your provider to DEFAULT_PROVIDERS:
import MyDriverProvider from "./providers/MyDriverProvider";
const DEFAULT_PROVIDERS = [
new OracleInstantClientProvider(),
new MyDriverProvider(),
];
That's it. The registry, manager, IPC handlers, and the
AutoDownloadButton UI will pick up the new provider automatically.
SettingsInput checks the registry by settingKey. When a provider is
found, it renders an AutoDownloadButton next to the field. Clicking it
opens the license + details modal (URL, install path, platform notes),
and accepting kicks off a download in the utility process whose
progress is streamed to a Noty toast.
The install path is written back to the matching UserSetting, so
existing driver code that already reads that setting needs no changes.
SettingsInput.~/.config/beekeeper-studio/driver-deps/<requirement-id>/.