Skip to main content

Overview

The Drizzle provider is a production-ready implementation of the ConversationStore interface using PostgreSQL and Drizzle ORM.

Installation

Install the required dependencies:

Database Schema

The provider uses two tables in the ff_ai schema:

threads Table

Stores conversation threads:
bigserial
Internal primary key (auto-incrementing)
text
Your application’s thread identifier (from ThreadIdentifier.threadId)
text
Your application’s resource identifier (from ThreadIdentifier.resourceId)
timestamp
When the thread was first created
timestamp
When the thread was last updated (any message activity)

messages Table

Stores individual messages:
bigserial
Internal primary key for efficient querying
uuid
The message’s public UUID (from ConversationMessage.id)
bigint
Foreign key to threads table (cascading delete)
jsonb
The complete AI SDK ModelMessage object (role, content, etc.)
timestamp
When the message was created

Setup

1. Create the Database Schema

Generate and run migrations:
Or create the schema manually:

2. Configure the Provider

3. Use in Your Application

API Reference

createDrizzleStoreLayer

Create a Layer that provides the ConversationStore service.
postgres.Sql
required
A postgres.js connection instance
'snake_case' | 'camelCase'
default:"undefined"
Database column naming convention. Set to 'snake_case' if your database uses snake_case naming.
Layer<ConversationStore>
An Effect Layer that provides the ConversationStore service

Implementation Details

Window Size Query

The provider implements the window size feature efficiently:
  1. Finds the thread by resourceId and publicId
  2. Queries for the N most recent user messages
  3. Identifies the oldest user message in the window
  4. Returns all messages (user, assistant, tool) from that point forward
This ensures you get complete conversation context including all assistant responses and tool interactions.

Transactions

The saveMessages method uses a database transaction to ensure atomicity:
This guarantees:
  • Thread is created/updated atomically with messages
  • Either all messages save or none do (no partial writes)
  • Thread updatedAt always reflects latest activity

Cascade Deletes

Messages are automatically deleted when their thread is deleted:
This simplifies conversation cleanup:

Performance Considerations

The schema includes essential indexes:
Consider adding:
Use connection pooling for better performance:
The aiSdkV5 column stores the complete message as JSONB:
  • Pros: Flexible schema, easy queries, no migration needed
  • Cons: Slightly slower than relational columns
For high-volume applications, consider:
  • Extracting frequently-queried fields to columns
  • Using JSONB operators for efficient queries
  • Adding GIN indexes for JSONB queries
Larger window sizes require more database queries:
  • Window size 10: ~50-100 messages typically returned
  • Window size 50: ~250-500 messages typically returned
Monitor query performance and adjust window sizes accordingly.

Troubleshooting

Ensure the ff_ai schema exists:
Check your connection string and network:
If you see column name errors, set the casing option:
Ensure threads are created before messages:

Migration from Other Stores

If you’re migrating from another storage system:

Next Steps

Turn Handler

Use the turn handler with Drizzle storage

Conversation Store

Learn about the store interface

Examples

See complete examples with Drizzle