The SQL plugin provides two database adapters that extend a common BaseDrizzleAdapter:

  • PGLite Adapter - Embedded PostgreSQL for development and testing
  • PostgreSQL Adapter - Full PostgreSQL for production environments

Architecture Overview

Both adapters share the same base functionality through BaseDrizzleAdapter, which implements the IDatabaseAdapter interface from @elizaos/core. The adapters handle:

  • Connection management through dedicated managers
  • Automatic retry logic for database operations
  • Schema introspection and dynamic migrations
  • Embedding dimension configuration (default: 384 dimensions)

PGLite Adapter

The PgliteDatabaseAdapter uses an embedded PostgreSQL instance that runs entirely in Node.js.

Key Features

  • Zero external dependencies - No PostgreSQL installation required
  • File-based persistence - Data stored in local filesystem
  • Singleton connection manager - Ensures single database instance per process
  • Automatic initialization - Database created on first use

Implementation Details

export class PgliteDatabaseAdapter extends BaseDrizzleAdapter {
  private manager: PGliteClientManager;
  protected embeddingDimension: EmbeddingDimensionColumn = DIMENSION_MAP[384];

  constructor(agentId: UUID, manager: PGliteClientManager) {
    super(agentId);
    this.manager = manager;
    this.db = drizzle(this.manager.getConnection());
  }
}

Connection Management

The PGliteClientManager handles:

  • Singleton PGLite instance creation
  • Data directory resolution and creation
  • Connection persistence across adapter instances

PostgreSQL Adapter

The PgDatabaseAdapter connects to a full PostgreSQL database using connection pooling.

Key Features

  • Connection pooling - Efficient resource management
  • Automatic retry logic - Built-in resilience for transient failures
  • Production-ready - Designed for scalable deployments
  • SSL support - Secure connections when configured
  • Cloud compatibility - Works with Supabase, Neon, and other PostgreSQL providers

Implementation Details

export class PgDatabaseAdapter extends BaseDrizzleAdapter {
  protected embeddingDimension: EmbeddingDimensionColumn = DIMENSION_MAP[384];
  private manager: PostgresConnectionManager;

  constructor(agentId: UUID, manager: PostgresConnectionManager, _schema?: any) {
    super(agentId);
    this.manager = manager;
    this.db = manager.getDatabase();
  }

  protected async withDatabase<T>(operation: () => Promise<T>): Promise<T> {
    return await this.withRetry(async () => {
      const client = await this.manager.getClient();
      try {
        const db = drizzle(client);
        this.db = db;
        return await operation();
      } finally {
        client.release();
      }
    });
  }
}

Connection Management

The PostgresConnectionManager provides:

  • Connection pool management (default size: 20)
  • SSL configuration based on environment
  • Singleton pattern to prevent multiple pools
  • Graceful shutdown handling

Adapter Selection

The adapter is automatically selected based on environment configuration:

export function createDatabaseAdapter(
  config: {
    dataDir?: string;
    postgresUrl?: string;
  },
  agentId: UUID
): IDatabaseAdapter {
  if (config.postgresUrl) {
    // PostgreSQL adapter for production
    if (!globalSingletons.postgresConnectionManager) {
      globalSingletons.postgresConnectionManager = new PostgresConnectionManager(
        config.postgresUrl
      );
    }
    return new PgDatabaseAdapter(agentId, globalSingletons.postgresConnectionManager);
  } else {
    // PGLite adapter for development
    const resolvedDataDir = resolvePgliteDir(config.dataDir);
    if (!globalSingletons.pgLiteClientManager) {
      globalSingletons.pgLiteClientManager = new PGliteClientManager(resolvedDataDir);
    }
    return new PgliteDatabaseAdapter(agentId, globalSingletons.pgLiteClientManager);
  }
}

Migration Handling

Important: Both adapters delegate migration handling to the DatabaseMigrationService. The adapters themselves do not run migrations directly.

// In both adapters:
async runMigrations(): Promise<void> {
  logger.debug('Migrations are handled by the migration service');
  // Migrations are handled by the migration service, not the adapter
}

The migration service handles:

  • Plugin schema discovery and registration
  • Dynamic table creation and updates
  • Schema introspection for existing tables
  • Dependency resolution for table creation order

Best Practices

Development (PGLite)

  1. Use default data directory for consistency
  2. Clear data directory between test runs if needed
  3. Be aware of file system limitations
  4. Suitable for single-instance development

Production (PostgreSQL)

  1. Always use connection pooling
  2. Configure SSL for secure connections
  3. Monitor connection pool usage
  4. Use environment variables for configuration
  5. Implement proper backup strategies

Configuration

The SQL plugin automatically selects the appropriate adapter based on environment variables.

Environment Variables

# .env file

# For PostgreSQL (production)
POSTGRES_URL=postgresql://user:password@host:5432/database

# For custom PGLite directory (optional)
# If not set, defaults to ./.eliza/.elizadb
PGLITE_DATA_DIR=/path/to/custom/db

Configuration Priority

  1. If POSTGRES_URL is set → Uses PostgreSQL adapter
  2. If POSTGRES_URL is not set → Uses PGLite adapter
    • With PGLITE_DATA_DIR if specified
    • Otherwise uses default path: ./.eliza/.elizadb

PostgreSQL Configuration

The PostgreSQL adapter supports any PostgreSQL-compatible database:

  • Supabase - Use the connection string from your project settings
  • Neon - Use the connection string from your Neon console
  • Amazon RDS PostgreSQL
  • Google Cloud SQL PostgreSQL
  • Self-hosted PostgreSQL (v12+)

Example connection strings:

# Supabase
POSTGRES_URL=postgresql://postgres:[password]@[project].supabase.co:5432/postgres

# Neon
POSTGRES_URL=postgresql://[user]:[password]@[project].neon.tech/[database]?sslmode=require

# Standard PostgreSQL
POSTGRES_URL=postgresql://user:password@localhost:5432/mydb

Error Handling

Both adapters include:

  • Automatic retry logic (3 attempts by default)
  • Exponential backoff between retries
  • Detailed error logging
  • Graceful degradation

The adapters handle common scenarios like:

  • Connection timeouts
  • Transient network failures
  • Pool exhaustion (PostgreSQL)
  • File system errors (PGLite)