Skip to main content

Overview

elizaOS uses Drizzle ORM with PostgreSQL/PGLite and features a powerful dynamic migration system that automatically manages database schema changes at runtime. This guide demonstrates how to add custom tables to your plugins, create repositories for data access, and build actions and providers to interact with your data.

Key Features

  • Automatic Migrations: Schema changes are detected and applied automatically
  • PGLite & PostgreSQL Support: Works with both databases seamlessly
  • Schema Isolation: Each plugin gets its own namespace to avoid conflicts
  • Safety First: Destructive changes are blocked in production by default
  • Zero Configuration: No manual migration files needed
Important: Drizzle ORM version in your plugin must match the monorepo version. Check packages/core/package.json for the exact version required.

Dynamic Migration System

Since ElizaOS 1.0, plugins can define schemas that are automatically migrated without any manual intervention. The system:
  1. Detects Changes: Compares your schema with the database state
  2. Generates SQL: Creates migration statements automatically
  3. Applies Safely: Runs migrations in transactions with rollback capability
  4. Tracks History: Maintains complete audit trail of all schema changes

Database Compatibility

| Database | Development | Production | Features | |------------|-------------|------------|-----------------------------------|| | PGLite | ✅ Recommended | ⚠️ Limited | Fast, in-memory, no setup needed | | PostgreSQL | ✅ Supported | ✅ Recommended | Full features, vector search, scaling |

Version Requirements

Critical: Your plugin’s Drizzle version must match the monorepo version:

Step 1: Define Your Custom Schema

Schema Namespacing

Important: Plugins should use namespaced schemas to avoid conflicts:
  • Core Plugin (@elizaos/plugin-sql): Uses the public schema
  • All Other Plugins: Must use plugin_<name> schema namespace

Creating a Shared Table

To create a table accessible by all agents (no agentId field):
Key Points:
  • Use pgSchema('plugin_yourname') for namespace isolation
  • Tables without agentId are shared across all agents
  • Migrations are generated and applied automatically at runtime
  • Indexes are created automatically with the table

Creating Agent-Specific Tables

For data that should be scoped to individual agents:

PGLite Compatibility Notes

Step 2: Create a Repository for Database Access

Repository Pattern

Create a repository class to handle database operations. This follows the pattern used throughout elizaOS:

Advanced Repository Patterns

Transactions

Complex Queries

Step 3: Create an Action to Write Data

Action Structure

Actions process user input and store data using the repository:

Batch Operations Action

Step 4: Create a Provider to Read Data

Provider Structure

Providers make data available to agents during conversations:

Caching Provider

Step 5: Register Your Components

Plugin Configuration

Register your schema with your plugin - migrations run automatically:

How Migrations Run

When your plugin loads:
  1. Schema Discovery: System finds your schema definition
  2. Diff Generation: Compares with current database state
  3. Safety Check: Blocks destructive changes in production
  4. Migration: Applies changes in a transaction
  5. Recording: Stores migration history in migrations schema

Important Considerations

1. Drizzle Version Matching

Critical: Your plugin must use the same Drizzle ORM version as the monorepo:
Mismatched versions can cause:
  • Migration generation failures
  • Type incompatibilities
  • Runtime errors
  • Schema sync issues

2. Schema Namespacing & Data Patterns

Without agentId in your tables:
  • All agents can read and write the same data
  • Use userId or other identifiers to scope data appropriately
  • Consider data consistency across multiple agents

3. Database Compatibility

4. Error Handling

5. Migration Behavior

Safe Changes (always allowed):
  • Adding new tables
  • Adding nullable columns
  • Adding indexes
  • Extending varchar length
Destructive Changes (require permission):
  • Dropping tables or columns
  • Changing column types
  • Adding NOT NULL to existing columns

Complete Example Workflow

1. Initial Setup

2. Define Your Schema

3. Register with Plugin

4. Runtime Flow

  1. Plugin Loads: Schema detected, migrations run automatically
  2. User Message: “I prefer dark theme and Spanish language”
  3. Action Executes: Stores preferences in database
  4. Provider Reads: Supplies preferences to agent context
  5. Multiple Agents: All agents access the same schema namespace

Advanced Patterns

Time-Series Data

Troubleshooting Common Issues

”Drizzle version mismatch” Error

”Schema already exists” in PGLite

”Destructive migration blocked” in Production

”Cannot find module ‘drizzle-orm/pg-core‘“

Migration Not Running

Summary

To add custom schema to an elizaOS plugin with automatic migrations:
  1. Match Drizzle Version: Use the same version as the monorepo (bun add drizzle-orm@^0.36.0)
  2. Use Schema Namespacing: Always use pgSchema('plugin_yourname') for isolation
  3. Define Your Tables: Create tables with or without agentId for scoping
  4. Register Schema: Add schema to plugin definition for automatic migrations
  5. Build Components: Create repositories, actions, and providers
  6. Let Migrations Run: System handles everything automatically on startup
No manual migration files needed! The dynamic migration system detects changes and applies them safely, with full rollback support and production safeguards.

See Also

Dynamic Migrations

Deep dive into the automatic migration system

Plugin Components

Learn about Actions, Providers, Evaluators, and Services

Development Guide

Build your first plugin step by step

Plugin Reference

Complete API reference for all interfaces