Skip to main content

Database Schema

warning

This tutorial is a community contribution and is not supported by the Open WebUI team. It serves only as a demonstration on how to customize Open WebUI for your specific use case. Want to contribute? Check out the contributing tutorial.

[!WARNING] This documentation was created/updated based on version 0.8.0 and updated for recent migrations.

Open-WebUI Internal SQLite Database

For Open-WebUI, the SQLite database serves as the backbone for user management, chat history, file storage, and various other core functionalities. Understanding this structure is essential for anyone looking to contribute to or maintain the project effectively.

Internal SQLite Location

You can find the SQLite database at root -> data -> webui.db

📁 Root (/)
├── 📁 data
│ ├── 📁 cache
│ ├── 📁 uploads
│ ├── 📁 vector_db
│ └── 📄 webui.db
├── 📄 dev.sh
├── 📁 open_webui
├── 📄 requirements.txt
├── 📄 start.sh
└── 📄 start_windows.bat

Copy Database Locally

If you want to copy the Open-WebUI SQLite database running in the container to your local machine, you can use:

docker cp open-webui:/app/backend/data/webui.db ./webui.db

Alternatively, you can access the database within the container using:

docker exec -it open-webui /bin/sh

Table Overview

Here is a complete list of tables in Open-WebUI's SQLite database. The tables are listed alphabetically and numbered for convenience.

No.Table NameDescription
01access_grantStores normalized access control grants for all resources
02authStores user authentication credentials and login information
03channelManages chat channels and their configurations
04channel_fileLinks files to channels and messages
05channel_memberTracks user membership and permissions within channels
06chatStores chat sessions and their metadata
07chat_fileLinks files to chats and messages
08chatidtagMaps relationships between chats and their associated tags
09configMaintains system-wide configuration settings
10documentStores documents and their metadata for knowledge management
11feedbackCaptures user feedback and ratings
12fileManages uploaded files and their metadata
13folderOrganizes files and content into hierarchical structures
14functionStores custom functions and their configurations
15groupManages user groups and their permissions
16group_memberTracks user membership within groups
17knowledgeStores knowledge base entries and related information
18knowledge_fileLinks files to knowledge bases
19memoryMaintains chat history and context memory
20messageStores individual chat messages and their content
21message_reactionRecords user reactions (emojis/responses) to messages
22migrate_historyTracks database schema version and migration records
23modelManages AI model configurations and settings
24noteStores user-created notes and annotations
25oauth_sessionManages active OAuth sessions for users
26promptStores templates and configurations for AI prompts
27prompt_historyTracks version history and snapshots for prompts
28skillStores reusable markdown instruction sets (Skills)
29tagManages tags/labels for content categorization
30toolStores configurations for system tools and integrations
31userMaintains user profiles and account information

Note: there are two additional tables in Open-WebUI's SQLite database that are not related to Open-WebUI's core functionality, that have been excluded:

  • Alembic Version table
  • Migrate History table

Now that we have all the tables, let's understand the structure of each table.

Access Grant Table

Column NameData TypeConstraintsDescription
idIntegerPRIMARY KEY, AUTOINCREMENTUnique identifier
resource_typeTextNOT NULLType of resource (e.g., model, knowledge, tool)
resource_idTextNOT NULLID of the specific resource
principal_typeTextNOT NULLType of grantee: user or group
principal_idTextNOT NULLID of the user or group (or * for public)
permissionTextNOT NULLPermission level: read or write
created_atBigIntegernullableGrant creation timestamp

Things to know about the access_grant table:

  • Unique constraint on (resource_type, resource_id, principal_type, principal_id, permission) to prevent duplicate grants
  • Indexed on (resource_type, resource_id) and (principal_type, principal_id) for efficient lookups
  • Replaces the former access_control JSON column that was previously embedded in each resource table
  • principal_type of user with principal_id of * represents public (open) access
  • Supports both group-level and individual user-level access grants

Auth Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier
emailString-User's email
passwordText-Hashed password
activeBoolean-Account status

Things to know about the auth table:

  • Uses UUID for primary key
  • One-to-One relationship with users table (shared id)

Channel Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idText-Owner/creator of channel
typeTextnullableChannel type
nameText-Channel name
descriptionTextnullableChannel description
dataJSONnullableFlexible data storage
metaJSONnullableChannel metadata

| created_at | BigInteger | - | Creation timestamp (nanoseconds) | | updated_at | BigInteger | - | Last update timestamp (nanoseconds) |

Things to know about the auth table:

  • Uses UUID for primary key
  • Case-insensitive channel names (stored lowercase)

Channel Member Table

Column NameData TypeConstraintsDescription
idTEXTNOT NULLUnique identifier for the channel membership
channel_idTEXTNOT NULLReference to the channel
user_idTEXTNOT NULLReference to the user
created_atBIGINT-Timestamp when membership was created

Channel File Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idTextNOT NULLOwner of the relationship
channel_idTextFOREIGN KEY(channel.id), NOT NULLReference to the channel
file_idTextFOREIGN KEY(file.id), NOT NULLReference to the file
message_idTextFOREIGN KEY(message.id), nullableReference to associated message
created_atBigIntegerNOT NULLCreation timestamp
updated_atBigIntegerNOT NULLLast update timestamp

Things to know about the channel_file table:

  • Unique constraint on (channel_id, file_id) to prevent duplicate entries
  • Foreign key relationships with CASCADE delete
  • Indexed on channel_id, file_id, and user_id for performance

Chat Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier (UUID)
user_idString-Owner of the chat
titleText-Chat title
chatJSON-Chat content and history
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp
share_idTextUNIQUE, nullableSharing identifier
archivedBooleandefault=FalseArchive status
pinnedBooleandefault=False, nullablePin status
metaJSONserver_default=""Metadata including tags
folder_idTextnullableParent folder ID

Chat File Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idTextNOT NULLUser associated with the file
chat_idTextFOREIGN KEY(chat.id), NOT NULLReference to the chat
file_idTextFOREIGN KEY(file.id), NOT NULLReference to the file
message_idTextnullableReference to associated message
created_atBigIntegerNOT NULLCreation timestamp
updated_atBigIntegerNOT NULLLast update timestamp

Things to know about the chat_file table:

  • Unique constraint on (chat_id, file_id) to prevent duplicate entries
  • Foreign key relationships with CASCADE delete
  • Indexed on chat_id, file_id, message_id, and user_id for performance

Why this table was added:

  • Query Efficiency: Before this, files were embedded in message objects. This table allows direct indexed lookups for finding all files in a chat without iterating through every message.
  • Data Consistency: Acts as a single source of truth for file associations. In multi-node deployments, all nodes query this table instead of relying on potentially inconsistent embedded data.
  • Deduplication: The database-level unique constraint prevents duplicate file associations, which is more reliable than application-level checks.

Chat ID Tag Table

Column NameData TypeConstraintsDescription
idVARCHAR(255)NOT NULLUnique identifier
tag_nameVARCHAR(255)NOT NULLName of the tag
chat_idVARCHAR(255)NOT NULLReference to chat
user_idVARCHAR(255)NOT NULLReference to user
timestampINTEGERNOT NULLCreation timestamp

Config

Column NameData TypeConstraintsDefaultDescription
idINTEGERNOT NULL-Primary key identifier
dataJSONNOT NULL-Configuration data
versionINTEGERNOT NULL-Config version number
created_atDATETIMENOT NULLCURRENT_TIMESTAMPCreation timestamp
updated_atDATETIME-CURRENT_TIMESTAMPLast update timestamp

Feedback Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idText-User who provided feedback
versionBigIntegerdefault=0Feedback version number
typeText-Type of feedback
dataJSONnullableFeedback data including ratings
metaJSONnullableMetadata (arena, chat_id, etc)
snapshotJSONnullableAssociated chat snapshot
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp

File Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier
user_idString-Owner of the file
hashTextnullableFile hash/checksum
filenameText-Name of the file
pathTextnullableFile system path
dataJSONnullableFile-related data
metaJSONnullableFile metadata

| created_at | BigInteger | - | Creation timestamp | | updated_at | BigInteger | - | Last update timestamp |

The meta field's expected structure:

{
"name": string, # Optional display name
"content_type": string, # MIME type
"size": integer, # File size in bytes
# Additional metadata supported via ConfigDict(extra="allow")
}

Folder Table

Column NameData TypeConstraintsDescription
idTextPK (composite)Unique identifier (UUID)
parent_idTextnullableParent folder ID for hierarchy
user_idTextPK (composite)Owner of the folder
nameText-Folder name
itemsJSONnullableFolder contents
dataJSONnullableAdditional folder data
metaJSONnullableFolder metadata
is_expandedBooleandefault=FalseUI expansion state
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp

Things to know about the folder table:

  • Primary key is composite (id, user_id)
  • Folders can be nested (parent_id reference)
  • Root folders have null parent_id
  • Folder names must be unique within the same parent

Function Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier
user_idString-Owner of the function
nameText-Function name
typeText-Function type
contentText-Function content/code
metaJSON-Function metadata
valvesJSON-Function control settings
is_activeBoolean-Function active status
is_globalBoolean-Global availability flag
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp

Things to know about the function table:

  • type can only be: ["filter", "action"]

Group Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEY, UNIQUEUnique identifier (UUID)
user_idText-Group owner/creator
nameText-Group name
descriptionText-Group description
dataJSONnullableAdditional group data
metaJSONnullableGroup metadata
permissionsJSONnullablePermission configuration
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp

Note: The user_ids column has been migrated to the group_member table.

Group Member Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEY, UNIQUEUnique identifier (UUID)
group_idTextFOREIGN KEY(group.id), NOT NULLReference to the group
user_idTextFOREIGN KEY(user.id), NOT NULLReference to the user
created_atBigIntegernullableCreation timestamp
updated_atBigIntegernullableLast update timestamp

Things to know about the group_member table:

  • Unique constraint on (group_id, user_id) to prevent duplicate memberships
  • Foreign key relationships with CASCADE delete to group and user tables

Knowledge Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEY, UNIQUEUnique identifier (UUID)
user_idText-Knowledge base owner
nameText-Knowledge base name
descriptionText-Knowledge base description
dataJSONnullableKnowledge base content
metaJSONnullableAdditional metadata

| created_at | BigInteger | - | Creation timestamp | | updated_at | BigInteger | - | Last update timestamp |

Knowledge File Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idTextNOT NULLOwner of the relationship
knowledge_idTextFOREIGN KEY(knowledge.id), NOT NULLReference to the knowledge base
file_idTextFOREIGN KEY(file.id), NOT NULLReference to the file
created_atBigIntegerNOT NULLCreation timestamp
updated_atBigIntegerNOT NULLLast update timestamp

Things to know about the knowledge_file table:

  • Unique constraint on (knowledge_id, file_id) to prevent duplicate entries
  • Foreign key relationships with CASCADE delete
  • Indexed on knowledge_id, file_id, and user_id for performance

Access control for resources (models, knowledge bases, tools, prompts, notes, files, channels) is managed through the access_grant table rather than embedded JSON. Each grant entry specifies a resource, a principal (user or group), and a permission level (read or write). See the Access Grant Table section above for details.

Memory Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier (UUID)
user_idString-Memory owner
contentText-Memory content
created_atBigInteger-Creation timestamp
updated_atBigInteger-Last update timestamp

Message Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idText-Message author
channel_idTextnullableAssociated channel
parent_idTextnullableParent message for threads
contentText-Message content
dataJSONnullableAdditional message data
metaJSONnullableMessage metadata
created_atBigInteger-Creation timestamp (nanoseconds)
updated_atBigInteger-Last update timestamp (nanoseconds)

Message Reaction Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idText-User who reacted
message_idText-Associated message
nameText-Reaction name/emoji
created_atBigInteger-Reaction timestamp

Model Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYModel identifier
user_idText-Model owner
base_model_idTextnullableParent model reference
nameText-Display name
paramsJSON-Model parameters
metaJSON-Model metadata

| is_active | Boolean | default=True | Active status | | created_at | BigInteger | - | Creation timestamp | | updated_at | BigInteger | - | Last update timestamp |

Note Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier
user_idTextnullableOwner of the note
titleTextnullableNote title
dataJSONnullableNote content and data
metaJSONnullableNote metadata

| created_at | BigInteger | nullable | Creation timestamp | | updated_at | BigInteger | nullable | Last update timestamp |

OAuth Session Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique session identifier
user_idTextFOREIGN KEY(user.id)Associated user
providerText-OAuth provider (e.g., 'google')
tokenText-OAuth session token
expires_atBigInteger-Token expiration timestamp
created_atBigInteger-Session creation timestamp
updated_atBigInteger-Session last update timestamp

Prompt Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
commandStringUNIQUE, INDEXUnique command identifier
user_idStringNOT NULLOwner of the prompt
nameTextNOT NULLDisplay name of the prompt
contentTextNOT NULLPrompt content/template
dataJSONnullableAdditional prompt data
metaJSONnullablePrompt metadata

| is_active | Boolean | default=True | Active status | | version_id | Text | nullable | Current version identifier | | tags | JSON | nullable | Associated tags | | created_at | BigInteger | NOT NULL | Creation timestamp | | updated_at | BigInteger | NOT NULL | Last update timestamp |

Prompt History Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
prompt_idTextFOREIGN KEY(prompt.id), INDEXReference to the prompt
parent_idTextnullableReference to the parent version
snapshotJSONNOT NULLSnapshot of the prompt at version
user_idTextNOT NULLUser who created the version
commit_messageTextnullableVersion commit message
created_atBigIntegerNOT NULLCreation timestamp

Skill Table

Column NameData TypeConstraintsDescription
idTextPRIMARY KEYUnique identifier (UUID)
user_idTextNOT NULLOwner/creator of the skill
nameTextNOT NULLDisplay name of the skill
descriptionTextnullableShort description (used in manifest)
contentTextNOT NULLFull skill instructions (Markdown)
dataJSONnullableAdditional skill data
metaJSONnullableSkill metadata
is_activeBooleandefault=TrueActive status
created_atBigIntegerNOT NULLCreation timestamp
updated_atBigIntegerNOT NULLLast update timestamp

Things to know about the skill table:

  • Uses UUID for primary key
  • Access control is managed through the access_grant table (resource_type skill)
  • description is injected into the system prompt as part of the manifest; content is loaded on-demand via the view_skill builtin tool

Tag Table

Column NameData TypeConstraintsDescription
idStringPK (composite)Normalized tag identifier
nameString-Display name
user_idStringPK (composite)Tag owner
metaJSONnullableTag metadata

Things to know about the tag table:

  • Primary key is composite (id, user_id)

Tool Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier
user_idString-Tool owner
nameText-Tool name
contentText-Tool content/code
specsJSON-Tool specifications
metaJSON-Tool metadata
valvesJSON-Tool control settings

| created_at | BigInteger | - | Creation timestamp | | updated_at | BigInteger | - | Last update timestamp |

User Table

Column NameData TypeConstraintsDescription
idStringPRIMARY KEYUnique identifier
usernameString(50)nullableUser's unique username
nameString-User's name
emailString-User's email
roleString-User's role
profile_image_urlText-Profile image path
bioTextnullableUser's biography
genderTextnullableUser's gender
date_of_birthDatenullableUser's date of birth
last_active_atBigInteger-Last activity timestamp
updated_atBigInteger-Last update timestamp
created_atBigInteger-Creation timestamp
api_keyStringUNIQUE, nullableAPI authentication key
settingsJSONnullableUser preferences
infoJSONnullableAdditional user info
oauth_subTextUNIQUEOAuth subject identifier
scimJSONnullableSCIM provisioning data

Things to know about the user table:

  • Uses UUID for primary key
  • One-to-One relationship with auth table (shared id)
  • One-to-One relationship with oauth_session table (via user_id foreign key)

The scim field's expected structure:

{
"<provider>": {
"external_id": string, # externalId from the identity provider
},
# Multiple providers can be stored simultaneously
# Example:
# "microsoft": { "external_id": "abc-123" },
# "okta": { "external_id": "def-456" }
}

Why this column was added:

  • SCIM account linking: Stores per-provider externalId values from SCIM provisioning, enabling identity providers (like Azure AD, Okta) to match users by their external identifiers rather than relying solely on email.
  • Multi-provider support: The per-provider key structure allows a single user to be provisioned from multiple identity providers simultaneously, each storing their own externalId.
  • OAuth fallback: When looking up a user by externalId, the system falls back to matching against oauth_sub if no scim entry is found, enabling seamless linking of SCIM-provisioned and OAuth-authenticated accounts.

Entity Relationship Diagram

To help visualize the relationship between the tables, refer to the below Entity Relationship Diagram (ERD) generated with Mermaid.


Database Encryption with SQLCipher

For enhanced security, Open WebUI supports at-rest encryption for its primary SQLite database using SQLCipher. This is recommended for deployments handling sensitive data where using a larger database like PostgreSQL is not needed.

Prerequisites

SQLCipher encryption requires additional dependencies that are not included by default. Before using this feature, you must install:

  • The SQLCipher system library (e.g., libsqlcipher-dev on Debian/Ubuntu, sqlcipher on macOS via Homebrew)
  • The sqlcipher3-wheels Python package (pip install sqlcipher3-wheels)

For Docker users, this means building a custom image with these dependencies included.

Configuration

To enable encryption, set the following environment variables:

# Required: Set the database type to use SQLCipher
DATABASE_TYPE=sqlite+sqlcipher

# Required: Set a secure password for database encryption
DATABASE_PASSWORD=your-secure-password

When these are set and a full DATABASE_URL is not explicitly defined, Open WebUI will automatically create and use an encrypted database file at ./data/webui.db.

Important Notes

danger
  • The DATABASE_PASSWORD environment variable is required when using sqlite+sqlcipher.
  • The DATABASE_TYPE variable tells Open WebUI which connection logic to use. Setting it to sqlite+sqlcipher activates the encryption feature.
  • Keep the password secure, as it is needed to decrypt and access all application data.
  • Losing the password means losing access to all data in the encrypted database.
Migrating Existing Data to SQLCipher

Open WebUI does not support automatic migration from an unencrypted SQLite database to an encrypted SQLCipher database. If you enable SQLCipher on an existing installation, the application will fail to read your existing unencrypted data.

To use SQLCipher with existing data, you must either:

  1. Start fresh - Enable SQLCipher on a new installation and have users export/re-import their chats manually
  2. Manual database migration - Use external SQLite/SQLCipher tools to export data from the unencrypted database and import it into a new encrypted database (advanced users only)
  3. Use filesystem-level encryption - Consider alternatives like LUKS (Linux) or BitLocker (Windows) for at-rest encryption without database-level changes
  4. Switch to PostgreSQL - For multi-user deployments, PostgreSQL with TLS provides encryption in transit and can be combined with encrypted storage
VariableDefaultDescription
DATABASE_TYPENoneSet to sqlite+sqlcipher for encrypted SQLite
DATABASE_PASSWORD-Encryption password (required for SQLCipher)
DATABASE_ENABLE_SQLITE_WALFalseEnable Write-Ahead Logging for better performance
DATABASE_POOL_SIZENoneDatabase connection pool size
DATABASE_POOL_TIMEOUT30Pool connection timeout in seconds
DATABASE_POOL_RECYCLE3600Pool connection recycle time in seconds

For more details, see the Environment Variable Configuration documentation.