Migrations#
ADK stores use standard SQLSpec migrations. Generate migrations for the database used by your ADK backend, then run them with the SQLSpec migration CLI.
Schema Bootstrapping#
You can programmatically create ADK session/event and memory tables with
create_tables() / ensure_tables():
await session_store.ensure_tables()
await memory_store.ensure_tables()
Alternatively, configure SQLSpec migrations on the database config and run the migration CLI ahead of deployment:
from sqlspec.adapters.asyncpg import AsyncpgConfig
config = AsyncpgConfig(
connection_config={"dsn": "postgresql://localhost/app"},
migration_config={"script_location": "migrations/postgres"},
)
sqlspec upgrade
Use the code path when the store should keep its tables current. On startup,
ensure_tables() checks the live tables. It creates missing tables and adds
new columns from the store DDL. It does not rename, drop, or change columns.
Control this behavior under extension_config["adk"]:
config = AsyncpgConfig(
connection_config={"dsn": "postgresql://localhost/app"},
extension_config={
"adk": {
"manage_schema": True,
"create_schema": True,
"run_migrations": False,
}
},
)
manage_schema=False turns off all automatic table changes.
create_schema=False lets the store add columns to current tables. It will
not create a missing table. run_migrations is for tools that supply a
versioned migration runner. That work stays separate from automatic checks.
For a release that only adds columns, update the adapter store DDL. You do not
need a schema seed or a numbered migration. Write a migration for renamed or
dropped columns, type changes, data backfills, and other complex work. Old
schema_version rows remain readable, but they do not control the schema.
Use versioned migrations when your release process needs a ledger. Also use them for changes that do more than add columns.
Note
The migration CLI resolves configuration from --config,
SQLSPEC_CONFIG, or [tool.sqlspec] in pyproject.toml.
When extension_config["adk"] is present, ADK extension migrations are
auto-included. Use migration_config={"exclude_extensions": ["adk"]}
to skip only ADK extension migrations, or
migration_config={"include_extensions": ["adk"]} to opt in explicitly
by extension name. Use migration_config={"enabled": False} to disable
migrations entirely for a given database config.
Feature Gating#
Your migration configuration decides whether ADK migrations run at all. Within
those migrations, enable_sessions and enable_memory are the only
per-feature switches:
config = AsyncpgConfig(
connection_config={"dsn": "postgresql://localhost/app"},
migration_config={"script_location": "migrations/postgres"},
extension_config={"adk": {"enable_sessions": True, "enable_memory": False}},
)
enable_sessions=False suppresses the session, event, state, and metadata
DDL. enable_memory=False suppresses the memory table DDL and its PostgreSQL
extension statements described below. Both default to True.
PostgreSQL pgvector Requirement#
PostgreSQL memory tables store embeddings in a VECTOR column, which the
pgvector extension provides. When memory is enabled on PostgreSQL, migration
0001_create_adk_tables runs CREATE EXTENSION IF NOT EXISTS vector
immediately before the first statement that uses the type. The statement is
idempotent, so re-running the migration against a database that already has the
extension succeeds.
SQL can only enable an extension the server already ships. Two things must be true before the migration runs:
The pgvector server files are installed on the PostgreSQL host, so the extension is listed in
pg_available_extensions.The role running the migration is allowed to create the extension.
On managed database services, ask your DBA or platform team to pre-provision
pgvector through the provider's supported extension workflow rather than
granting broad privileges to the migration role. A pre-provisioned extension
costs nothing: the migration's IF NOT EXISTS statement becomes a no-op.
If either requirement is unmet, the migration fails on the CREATE EXTENSION
statement with a clear permission or availability error instead of a later
type "vector" does not exist error from the memory table DDL.
Automatic create_tables() / ensure_tables() reconciliation never
attempts extension installation, so it runs no repeated startup privilege
check. Deployments that rely on that path instead of versioned migrations must
pre-provision pgvector themselves.
PostgreSQL BM25 Requirement#
When enable_bm25=True, the same migration runs
CREATE EXTENSION IF NOT EXISTS pg_textsearch before creating the BM25
index. This is the extension used by AlloyDB for PostgreSQL 17 and 18 as well
as PostgreSQL installations that package pg_textsearch. ParadeDB's
pg_search extension does not satisfy this requirement.
As with pgvector, the server must provide the extension and the migration role
must be allowed to enable it. On managed AlloyDB, run the migration as a role
with the documented alloydbsuperuser privileges or have an administrator
pre-provision pg_textsearch. The idempotent migration statement is then a
no-op. Automatic table reconciliation never attempts to enable it.
Clean-Break Migration Notes#
If you are upgrading from a pre-clean-break version of the ADK extension, note the following schema changes:
Events table: The column layout changed to full-event JSON storage. Legacy pre-clean-break schemas used
event_jsonfor the event payload. The clean-break schema stores the full ADK Event inevent_dataalongside indexed scalar columns (id,app_name,user_id,session_id,invocation_id,timestamp).Artifact table: New table (
adk_artifact) for artifact metadata. Create this table when enabling the artifact service.BigQuery: Removed. Migrate to Spanner, PostgreSQL, or any other supported backend.
See Migrations for the full workflow and commands.