Add Your Database to Ptah with a Plugin
Build a database plugin on Ptah's provider API, or use the official YDB, Spanner, and DuckDB plugins. See the capabilities and a complete DuckDB example.
Ptah helps you plan, review, and apply database migrations. Try in your browser
You can add support for your database to Ptah with a plugin in its own repository. Your team can build, test, and release that integration on its own cycle. Ptah supplies the schema and migration workflow; your plugin supplies the database connection and the engine-specific behavior that workflow needs.
Three official plugins already use this approach: YDB, Spanner, and DuckDB. Each is installed separately from Ptah. They show that the provider API can serve a remote database, a PostgreSQL-interface service, and an embedded database with a native library. The same API is available to authors of other database integrations.
What a database plugin can provide
Section titled “What a database plugin can provide”A plugin does more than open a connection. It describes the engine’s objects and rules so Ptah can inspect a database, compare it with a desired schema, plan a change, and run the parts that engine supports. The author chooses which capabilities to implement and declares them to the host.
| In your plugin | What Ptah can do with it |
|---|---|
| Connection and catalog reading | Reach a new database engine and inspect the tables, columns, indexes, and other objects your plugin understands. |
| Native objects and properties | Model features such as YDB topics or partitioning settings alongside common tables and columns. Ptah can retain and compare those details instead of discarding them. |
| Comparison, planning, and execution rules | Account for the engine’s permitted changes, render its SQL or native operations, take locks where supported, and report execution outcomes. |
| SQL analysis and lint rules | Split and analyze statements using the engine’s syntax, validate declarations, and report dialect-specific problems. |
| Optional data services | Add row reads, seed data, write rendering, or an embedding store when the integration needs them. |
A plugin advertises its features. Ptah uses only the services it offers and refuses a command that needs a missing one. This is an extension point for database support and database-specific behavior within Ptah’s existing workflow. The models and planning guide explains how providers describe native objects, properties, and planning rules.
Three official plugins already use the API
Section titled “Three official plugins already use the API”| Plugin | What you can do | Scope to keep in mind |
|---|---|---|
| YDB | Manage schemas and versioned migrations with YDB-specific objects and rules, including topics. | The published provider certifies YDB 25.1 and 26.2. |
| Spanner | Use Ptah’s schema workflow through the separate Spanner provider. | The published provider covers its documented best-effort subset. |
| DuckDB | Inspect and change an embedded database file or in-memory database, and run versioned migrations. | The published provider serves embedded mode; MotherDuck and other network services are outside its scope. |
The DuckDB plugin is a concrete example of independent development. It links the native DuckDB library through CGO, while the Ptah executable has no DuckDB dependency and remains CGO-free. The plugin owns file sessions and reports lock conflicts. A team adding another engine can keep its driver and release packaging with its own integration, while using Ptah’s common workflow.
YDB and Spanner were moved from the host under the provider delivery task. DuckDB was delivered through a separate task using the same public contract. Their different support scopes are documented by each plugin.
Try a complete schema change with DuckDB
Section titled “Try a complete schema change with DuckDB”This example uses a local DuckDB file, so it needs no database server. Save
the desired schema as schema.sql:
CREATE TABLE events ( id BIGINT PRIMARY KEY, source VARCHAR(80) NOT NULL);Install the official DuckDB plugin and check that Ptah can start it:
ptah providers install duckdb --version 0.2.0ptah providers check --provider-engine duckdbPreview the change against a disposable file named demo.duckdb:
ptah schema apply --db-url duckdb://./demo.duckdb --schema-file schema.sql --dry-runThe preview includes this plan:
-- DUCKDB: column "source" of table "events" is declared VARCHAR(80); DuckDB keeps no length and holds it as VARCHAR, which takes text of any length.CREATE TABLE "main"."events" ( "id" BIGINT NOT NULL, "source" VARCHAR NOT NULL, PRIMARY KEY ("id"));The plugin supplied that warning because DuckDB accepts VARCHAR(80) but
stores the column as unrestricted VARCHAR. Ptah shows what will actually
be created before it changes the file. Apply the change, inspect the database,
and preview again:
ptah schema apply --db-url duckdb://./demo.duckdb --schema-file schema.sql --auto-approveptah schema inspect --db-url duckdb://./demo.duckdb --format sqlptah schema apply --db-url duckdb://./demo.duckdb --schema-file schema.sql --dry-runInspection reads the table back as DuckDB holds it:
CREATE TABLE "main"."events" ( "id" BIGINT NOT NULL, "source" VARCHAR NOT NULL, PRIMARY KEY ("id"));The last preview reports:
Schema is synced, no changes to be made.The plan, execution, readback, and second comparison all used the DuckDB plugin. The type note and the empty second plan show the difference between declared SQL and what this engine actually preserves. The example files record the released binaries and full command results.
How Ptah and a plugin divide the work
Section titled “How Ptah and a plugin divide the work”Ptah keeps the shared workflow. It selects a provider, reads desired schema sources, coordinates comparison, orders and saves plans, applies migration history rules, and presents results. The plugin connects to its database, reads its catalog, interprets native objects and SQL, and executes changes.
| Ptah host | Database plugin |
|---|---|
| Selects the executable and checks its identity and declared features | Describes its engines, services, and database-specific rules |
| Coordinates the common schema and migration workflow | Inspects the database and renders or plans changes it owns |
| Orders plans and reports results | Executes changes, handles engine locks, and reports outcomes |
| Treats incomplete inspection as incomplete | Reports what the database account could and could not see |
That last row matters. If a database account cannot see an object, Ptah must not conclude that the object was deleted and plan to remove it. A provider reports coverage so the host can refuse an unsafe comparison. Unsupported objects and changes should also produce explicit refusals rather than a plausible but incorrect plan.
Ptah launches a selected plugin as a separate process and exchanges versioned messages over local gRPC. It checks the executable’s digest before starting it, then verifies its identity and required features. The process has the operator’s permissions, so its executable must be trusted. The architecture guide describes the protocol and lifecycle in detail.
Build a plugin for your database
Section titled “Build a plugin for your database”The provider SDK
is a separate Go module with protocol types, a serving runtime, validators,
and a conformance suite. The minimal-provider
tutorial starts
from an empty module and ends with a custom engine creating a table through
ptah schema apply.
Start by choosing an engine name and database address. Implement the
connection, catalog inspection, change rendering and execution, and SQL
analysis that a working provider needs. Add native objects, comparison
rules, migrations, lint, or data services for the scope your engine supports.
Build the executable, select it with an explicit manifest that names its
identity and SHA-256 digest, and run ptah providers check. Then use the
SDK’s conformance suite and live database tests before publishing a release.
The executable providers
guide covers the
manifest and selection rules. ptah providers install serves the official
catalog; a custom plugin uses a manifest.
The API is versioned. A plugin declares the minimum contract it needs, and Ptah checks compatibility and features before opening a database. Pin versions you have tested together when releasing your integration.
Go is a convenient starting point because its SDK handles the process bootstrap. The wire protocol also permits providers written in other languages. A non-Go author currently implements the documented bootstrap and gRPC services directly; runnable examples are still to come. We will cover that work in future articles. The open language-example task and related issues for manifest arguments, a working directory, and manifest checksums would make the path easier.
To use a ready integration, choose the YDB, Spanner, or DuckDB guide. To add your own engine, follow the provider tutorial and run the conformance suite against your executable.