How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.
IMP uses a schema-per-boot initialisation model rather than a migration framework. Understanding how it works helps you operate the database safely and restore quickly from a backup.
IMP does not use Knex migrations, Flyway, Liquibase, or any versioned migration tool for its application schema. Instead, npm run utils:initdb runs on every backend and worker boot.The routine:
Attempts to auto-create the database if it does not exist (requires CREATEDB privilege).
Creates the vector extension if absent.
Iterates over every known table schema and either creates the table (if missing) or adds any missing columns with ALTER TABLE … ADD COLUMN IF NOT EXISTS.
Runs any one-time data migrations, each gated behind a column-existence check so they are no-ops after their first successful run.
Creates the admin and default roles if they do not exist.
Creates the default admin user (admin@exulu.com) if it does not exist.
Generates and logs a one-time API key.
This design means the database schema is always current after a boot, and there is nothing to run manually when you upgrade. A failing initdb step is a hard error — the backend exits rather than booting with an incomplete schema.
The first boot is the only moment the API key is ever persisted. Capture it before the log scrolls away:
docker logs exulu-backend 2>&1 | grep -A 5 "Default api key"
initdb generates a fresh key on every boot and logs it every time, but only the key from the very first startup is stored in the database. Keys logged on subsequent startups are never inserted and will not authenticate.
On first boot, initdb creates:
An admin role with full write access to all permission keys.
A default role with limited read access.
A default admin user with email admin@exulu.com and password admin.
One API key scoped to api@exulu.com.
Change the admin password immediately after first login. Navigate to your user settings and set a strong password. The default admin password is written in plain text in this documentation and in the source code.
Old installs may have data in columns that have been superseded. These migrations are embedded directly in initdb and run exactly once, gated on a column-existence check:
IMP stores tool credentials (API keys, usernames, passwords entered in agent tool forms) in the user_credentials table. Each row holds an AES-encrypted JSON blob keyed off NEXTAUTH_SECRET; the raw credential values are never stored in plain text.The data column is write-only at the API layer — list endpoints return provider name, auth type, and timestamps only; the encrypted blob never leaves the backend.
Rotating NEXTAUTH_SECRET breaks stored tool credentials. Because each blob is encrypted with the current secret, changing NEXTAUTH_SECRET makes every previously stored credential undecryptable. Tool calls that use those credentials will fail with an error until the affected rows are removed from user_credentials (users can then reconnect from chat or Settings → Connections).
On every boot, initdb drops the legacy oauth_tokens table unconditionally (DROP TABLE IF EXISTS oauth_tokens CASCADE) before creating (or leaving intact) the replacement user_credentials table. No data migration is required — the legacy table had no production users.
The LiteLLM proxy maintains its own schema in a separate Postgres database (set via LITELLM_DATABASE_URL in config.litellm.yaml). On every boot, IMP runs a guarded prisma db push against that database to keep the LiteLLM schema up to date.The push is skipped with a loud warning banner if:
LITELLM_DATABASE_URL points at the same host, port, and database name as the IMP application database.
The target database contains tables that do not start with LiteLLM_ (indicating it is not a dedicated LiteLLM database).
In either case, the backend continues booting but LiteLLM-dependent features (model routing, budget tracking, spend logging) fail at runtime. See LiteLLM service for the full warning and setup instructions.
IMP creates additional tables for each knowledge context (e.g., projects_items, projects_chunks). These tables include a vector(N) column whose dimensionality comes from the dimensionality field of the configured embedding model in config.litellm.yaml.Changing the embedding model after context tables exist requires migrating or recreating those tables — pgvector column dimensionality is fixed at creation time. There is no automated path for this today; back up and plan the migration manually.
The IMP schema is re-created by initdb on first boot, so you can also restore to an empty database and let initdb handle structure. However, restoring from a dump is faster and preserves pgvector indexes.
All uploaded files — session attachments, knowledge documents, and audio recordings — live in the COMPANION_S3_BUCKET. Back it up using your S3-compatible provider’s tooling. For MinIO:
mc mirror minio/<bucket-name> /local/backup/minio/<bucket-name>
A daily backup of both Postgres databases and the S3 bucket is the minimum for production deployments. Before any IMP upgrade, take a manual backup so you have a clean snapshot to roll back to if a migration behaves unexpectedly.
{"docsConfig":{"theme":"aspen","$schema":"https://mintlify.com/docs.json","name":"IMP Docs","description":"Documentation for IMP — the Intelligence Management Platform.","colors":{"primary":"#6f9a37","light":"#cef79e","dark":"#557a26"},"logo":{"light":"https://mintcdn.com/exulu/AoxglAoKLnpiSWrg/logo/imp-wordmark-light.svg?fit=max\u0026auto=format\u0026n=AoxglAoKLnpiSWrg\u0026q=85\u0026s=9b42068ec92bdc8c9edbfd0a097c1103","dark":"https://mintcdn.com/exulu/AoxglAoKLnpiSWrg/logo/imp-wordmark-dark.svg?fit=max\u0026auto=format\u0026n=AoxglAoKLnpiSWrg\u0026q=85\u0026s=a84a8146d264791641105aafa8cfce99"},"favicon":"https://mintcdn.com/exulu/AoxglAoKLnpiSWrg/logo/imp-icon.svg?fit=max\u0026auto=format\u0026n=AoxglAoKLnpiSWrg\u0026q=85\u0026s=7ac4f534736be19d46aa980180530371","background":{"color":{"light":"#f8f6f1","dark":"#1b1714"}},"footer":{"links":[{"header":"IMP","items":[{"label":"Intelligence Management Platform","href":"/get-started/what-is-imp"}]}]},"icons":{"library":"lucide"},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"exulu","hasAudioNarration":false,"actualSubdomain":"exulu","customDomains":["docs.intelligence-management-platform.com"],"gitSource":{"type":"github","owner":"qventu","repo":"exulu-backend","deployBranch":"main","contentDirectory":"mintlify-docs","isPrivate":false,"mountPath":"","label":""},"feedback":{"thumbs":true,"edits":true,"issues":true},"entitlements":{},"buildId":"6ad7083d07bd205c1a9ff19c","clientVersion":"0.0.4094","searchFilterCounts":[{"language":"default","tag":"API Reference","count":101},{"language":"default","tag":"REST","count":73},{"language":"default","tag":"Developers","count":54},{"language":"default","tag":"Building","count":24},{"language":"default","tag":"Core classes","count":24},{"language":"default","tag":"Core types","count":23},{"language":"default","tag":"User Guide","count":21},{"language":"default","tag":"Self-Hosting","count":16},{"language":"default","tag":"Skills","count":16},{"language":"default","tag":"Chat","count":15}]},"assistantConfig":{},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"styles.css","content":"@font-face{font-family:\"Aspekta\";font-style:normal;font-weight:400;src:url(\"/fonts/inter-tight-400.woff2\") format(\"woff2\");font-display:swap}@font-face{font-family:\"Aspekta\";font-style:normal;font-weight:500;src:url(\"/fonts/inter-tight-500.woff2\") format(\"woff2\");font-display:swap}@font-face{font-family:\"RobotoMono\";font-style:normal;font-weight:400;src:url(\"/fonts/roboto-mono-400.woff2\") format(\"woff2\");font-display:swap}:root{--imp-bone: #f8f6f1;--imp-ink: #222f30;--imp-void: #1b1714;--imp-tissue: #efece4;--imp-lime: #cef79e;--imp-olive: #6f9a37;--imp-hair-light: #e4ddd0;--imp-hair-dark: #4d5757}body{font-family:\"Aspekta\", \"Inter Tight\", system-ui, sans-serif;letter-spacing:-0.011em}h1,h2,h3,h4{font-family:\"Aspekta\", \"Inter Tight\", system-ui, sans-serif;font-weight:500;letter-spacing:-0.03em}code,pre,kbd,samp{font-family:\"RobotoMono\", \"Roboto Mono\", ui-monospace, monospace}*,*::before,*::after{border-radius:0!important}"}],"page":{"pagePath":"self-hosting/database","slug":"/self-hosting/database","pageMetadata":{"title":"Database","description":"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.","icon":"database","href":"/self-hosting/database"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`IMP uses a schema-per-boot initialisation model rather than a migration framework. Understanding how it works helps you operate the database safely and restore quickly from a backup.`}),`\n`,_jsx(Heading,{level:`2`,id:`the-no-migration-model`,children:`The no-migration model`}),`\n`,_jsxs(_components.p,{children:[`IMP does not use Knex migrations, Flyway, Liquibase, or any versioned migration tool for its application schema. Instead, `,_jsx(_components.code,{children:`npm run utils:initdb`}),` runs on `,_jsx(_components.strong,{children:`every`}),` backend and worker boot.`]}),`\n`,_jsx(_components.p,{children:`The routine:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Attempts to auto-create the database if it does not exist (requires `,_jsx(_components.code,{children:`CREATEDB`}),` privilege).`]}),`\n`,_jsxs(_components.li,{children:[`Creates the `,_jsx(_components.code,{children:`vector`}),` extension if absent.`]}),`\n`,_jsxs(_components.li,{children:[`Iterates over every known table schema and either creates the table (if missing) or adds any missing columns with `,_jsx(_components.code,{children:`ALTER TABLE … ADD COLUMN IF NOT EXISTS`}),`.`]}),`\n`,_jsx(_components.li,{children:`Runs any one-time data migrations, each gated behind a column-existence check so they are no-ops after their first successful run.`}),`\n`,_jsxs(_components.li,{children:[`Creates the `,_jsx(_components.code,{children:`admin`}),` and `,_jsx(_components.code,{children:`default`}),` roles if they do not exist.`]}),`\n`,_jsxs(_components.li,{children:[`Creates the default admin user (`,_jsx(_components.code,{children:`admin@exulu.com`}),`) if it does not exist.`]}),`\n`,_jsx(_components.li,{children:`Generates and logs a one-time API key.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`This design means the database schema is always current after a boot, and there is nothing to run manually when you upgrade. A failing initdb step is a hard error — the backend exits rather than booting with an incomplete schema.`}),`\n`,_jsx(Heading,{level:`2`,id:`first-boot-bootstrap`,children:`First-boot bootstrap`}),`\n`,_jsxs(Warning,{children:[_jsx(_components.p,{children:`The first boot is the only moment the API key is ever persisted. Capture it before the log scrolls away:`}),_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`docker`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` logs`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` exulu-backend`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` 2>\u00261`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` |`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:` grep`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -A`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#B5CEA8`},children:` 5`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` \"Default api key\"`})]}),`\n`]})})}),_jsxs(_components.p,{children:[_jsx(_components.code,{children:`initdb`}),` generates a fresh key on `,_jsx(_components.strong,{children:`every`}),` boot and logs it every time, but only the key from the very first startup is stored in the database. Keys logged on subsequent startups are never inserted and will not authenticate.`]})]}),`\n`,_jsx(_components.p,{children:`On first boot, initdb creates:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[`An `,_jsx(_components.code,{children:`admin`}),` role with full write access to all permission keys.`]}),`\n`,_jsxs(_components.li,{children:[`A `,_jsx(_components.code,{children:`default`}),` role with limited read access.`]}),`\n`,_jsxs(_components.li,{children:[`A default admin user with email `,_jsx(_components.code,{children:`admin@exulu.com`}),` and password `,_jsx(_components.code,{children:`admin`}),`.`]}),`\n`,_jsxs(_components.li,{children:[`One API key scoped to `,_jsx(_components.code,{children:`api@exulu.com`}),`.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Change the admin password immediately after first login.`}),` Navigate to your user settings and set a strong password. The default `,_jsx(_components.code,{children:`admin`}),` password is written in plain text in this documentation and in the source code.`]}),`\n`,_jsx(Heading,{level:`2`,id:`one-time-data-migrations`,children:`One-time data migrations`}),`\n`,_jsxs(_components.p,{children:[`Old installs may have data in columns that have been superseded. These migrations are embedded directly in `,_jsx(_components.code,{children:`initdb`}),` and run exactly once, gated on a column-existence check:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`5`,language:`typescript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`typescript`,children:_jsxs(_components.code,{language:`typescript`,numberOfLines:`5`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`const`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#4FC1FF`},children:` hasOldProviderCol`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` =`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:` await`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` knex`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`schema`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#8250DF`,\"--shiki-dark\":`#DCDCAA`},children:`hasColumn`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"agents\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"provider\"`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#C586C0`},children:`if`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` (`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:`hasOldProviderCol`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` ||`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#9CDCFE`},children:` hasOldKeyCol`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`) {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` // migrate agents.provider/providerapikey → models table`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` // drops old columns on completion`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`}`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`After the migration runs and drops the old columns, the block becomes a permanent no-op. No state outside the database is required.`}),`\n`,_jsx(Heading,{level:`2`,id:`tool-credential-store`,children:`Tool credential store`}),`\n`,_jsxs(_components.p,{children:[`IMP stores tool credentials (API keys, usernames, passwords entered in agent tool forms) in the `,_jsx(_components.code,{children:`user_credentials`}),` table. Each row holds an AES-encrypted JSON blob keyed off `,_jsx(_components.code,{children:`NEXTAUTH_SECRET`}),`; the raw credential values are never stored in plain text.`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`data`}),` column is write-only at the API layer — list endpoints return provider name, auth type, and timestamps only; the encrypted blob never leaves the backend.`]}),`\n`,_jsx(Warning,{children:_jsxs(_components.p,{children:[_jsxs(_components.strong,{children:[`Rotating `,_jsx(_components.code,{children:`NEXTAUTH_SECRET`}),` breaks stored tool credentials.`]}),` Because each blob is encrypted with the current secret, changing `,_jsx(_components.code,{children:`NEXTAUTH_SECRET`}),` makes every previously stored credential undecryptable. Tool calls that use those credentials will fail with an error until the affected rows are removed from user_credentials (users can then reconnect from chat or Settings → Connections).`]})}),`\n`,_jsxs(_components.p,{children:[`On every boot, initdb drops the legacy `,_jsx(_components.code,{children:`oauth_tokens`}),` table unconditionally (`,_jsx(_components.code,{children:`DROP TABLE IF EXISTS oauth_tokens CASCADE`}),`) before creating (or leaving intact) the replacement `,_jsx(_components.code,{children:`user_credentials`}),` table. No data migration is required — the legacy table had no production users.`]}),`\n`,_jsx(Heading,{level:`2`,id:`litellm-database`,children:`LiteLLM database`}),`\n`,_jsxs(_components.p,{children:[`The LiteLLM proxy maintains its own schema in a `,_jsx(_components.strong,{children:`separate`}),` Postgres database (set via `,_jsx(_components.code,{children:`LITELLM_DATABASE_URL`}),` in `,_jsx(_components.code,{children:`config.litellm.yaml`}),`). On every boot, IMP runs a guarded `,_jsx(_components.code,{children:`prisma db push`}),` against that database to keep the LiteLLM schema up to date.`]}),`\n`,_jsx(_components.p,{children:`The push is skipped with a loud warning banner if:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsxs(_components.li,{children:[_jsx(_components.code,{children:`LITELLM_DATABASE_URL`}),` points at the same host, port, and database name as the IMP application database.`]}),`\n`,_jsxs(_components.li,{children:[`The target database contains tables that do not start with `,_jsx(_components.code,{children:`LiteLLM_`}),` (indicating it is not a dedicated LiteLLM database).`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`In either case, the backend continues booting but LiteLLM-dependent features (model routing, budget tracking, spend logging) fail at runtime. See `,_jsx(_components.a,{href:`/self-hosting/services/litellm`,children:`LiteLLM service`}),` for the full warning and setup instructions.`]}),`\n`,_jsx(Heading,{level:`2`,id:`per-context-tables`,children:`Per-context tables`}),`\n`,_jsxs(_components.p,{children:[`IMP creates additional tables for each knowledge context (e.g., `,_jsx(_components.code,{children:`projects_items`}),`, `,_jsx(_components.code,{children:`projects_chunks`}),`). These tables include a `,_jsx(_components.code,{children:`vector(N)`}),` column whose dimensionality comes from the `,_jsx(_components.code,{children:`dimensionality`}),` field of the configured embedding model in `,_jsx(_components.code,{children:`config.litellm.yaml`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`Changing the embedding model after context tables exist requires migrating or recreating those tables — `,_jsx(_components.code,{children:`pgvector`}),` column dimensionality is fixed at creation time. There is no automated path for this today; back up and plan the migration manually.`]}),`\n`,_jsx(Heading,{level:`2`,id:`backup`,children:`Backup`}),`\n`,_jsx(_components.p,{children:`IMP data lives in two places: the Postgres databases and the S3 bucket. Both require regular backups.`}),`\n`,_jsx(Heading,{level:`3`,id:`postgres`,children:`Postgres`}),`\n`,_jsx(_components.p,{children:`Back up both the IMP application database and the LiteLLM database:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`pg_dump`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -h`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`hos`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -U`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`use`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`r`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -Fc`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`POSTGRES_DB_NAM`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`E`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` >`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` imp-`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`$(`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`date`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` +%Y%m%d`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`.dump`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`pg_dump`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -h`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`hos`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -U`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`use`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`r`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -Fc`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` litellm`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` >`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` litellm-`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`$(`}),_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`date`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` +%Y%m%d`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`)`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`.dump`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Restore with:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`pg_restore`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -h`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`hos`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -U`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`use`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`r`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`POSTGRES_DB_NAM`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`E`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` imp-20260114.dump`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`pg_restore`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -h`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`hos`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`t`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -U`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` \u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`use`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`r`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:` -d`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` litellm`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` litellm-20260114.dump`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The IMP schema is re-created by initdb on first boot, so you can also restore to an empty database and let initdb handle structure. However, restoring from a dump is faster and preserves pgvector indexes.`}),`\n`,_jsx(Heading,{level:`3`,id:`s3-bucket`,children:`S3 bucket`}),`\n`,_jsxs(_components.p,{children:[`All uploaded files — session attachments, knowledge documents, and audio recordings — live in the `,_jsx(_components.code,{children:`COMPANION_S3_BUCKET`}),`. Back it up using your S3-compatible provider’s tooling. For MinIO:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`mc`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` mirror`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` minio/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`bucket-nam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` /local/backup/minio/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`bucket-nam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`For AWS S3 or compatible:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`shellscript`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`shellscript`,children:_jsxs(_components.code,{language:`shellscript`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#953800`,\"--shiki-dark\":`#DCDCAA`},children:`aws`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` s3`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` sync`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` s3://`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`bucket-nam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` /local/backup/`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`bucket-nam`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`e`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`3`,id:`backup-cadence`,children:`Backup cadence`}),`\n`,_jsx(_components.p,{children:`A daily backup of both Postgres databases and the S3 bucket is the minimum for production deployments. Before any IMP upgrade, take a manual backup so you have a clean snapshot to roll back to if a migration behaves unexpectedly.`})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Database","description":"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.","icon":"database","href":"/self-hosting/database"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"The no-migration model","slug":"the-no-migration-model","depth":2,"children":[]},{"title":"First-boot bootstrap","slug":"first-boot-bootstrap","depth":2,"children":[]},{"title":"One-time data migrations","slug":"one-time-data-migrations","depth":2,"children":[]},{"title":"Tool credential store","slug":"tool-credential-store","depth":2,"children":[]},{"title":"LiteLLM database","slug":"litellm-database","depth":2,"children":[]},{"title":"Per-context tables","slug":"per-context-tables","depth":2,"children":[]},{"title":"Backup","slug":"backup","depth":2,"children":[{"title":"Postgres","slug":"postgres","depth":3,"children":[]},{"title":"S3 bucket","slug":"s3-bucket","depth":3,"children":[]},{"title":"Backup cadence","slug":"backup-cadence","depth":3,"children":[]}]}],"codeExamples":{}},"jsLinks":[],"subdomain":"exulu","siteName":"IMP Docs","title":"Database - IMP Docs","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-07-24T14:45:55.202Z","originalFileLocation":"self-hosting/database.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\">\u003cmeta data-mint-head name=\"application-name\" content=\"IMP Docs\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Database - IMP Docs\">\u003cmeta data-mint-head property=\"og:description\" content=\"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"IMP Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.intelligence-management-platform.com/self-hosting/database\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://exulu.mintlify.site/_mintlify/api/og/v2?division=Operate\u0026amp;title=Database\u0026amp;description=How+IMP+manages+its+Postgres+schema%3A+the+no-migration-framework+model%2C+idempotent+initdb%2C+first-boot+bootstrap%2C+and+backup+strategy.\u0026amp;theme=0a86c3c8bb60ae0aa06a3652\u0026amp;signature=df031212301d48ec4cd1b00e13af0ad7a25f539dbc0035077949416aa309f11e\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Database - IMP Docs\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://exulu.mintlify.site/_mintlify/api/og/v2?division=Operate\u0026amp;title=Database\u0026amp;description=How+IMP+manages+its+Postgres+schema%3A+the+no-migration-framework+model%2C+idempotent+initdb%2C+first-boot+bootstrap%2C+and+backup+strategy.\u0026amp;theme=0a86c3c8bb60ae0aa06a3652\u0026amp;signature=df031212301d48ec4cd1b00e13af0ad7a25f539dbc0035077949416aa309f11e\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/exulu/N9cNIKTf5pwOldAi/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"IMP Docs\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#6f9a37\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.intelligence-management-platform.com/self-hosting/database\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/self-hosting/database.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.intelligence-management-platform.com/#organization\",\"name\":\"IMP Docs\",\"url\":\"https://docs.intelligence-management-platform.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/exulu/AoxglAoKLnpiSWrg/logo/imp-wordmark-light.svg?fit=max\u0026auto=format\u0026n=AoxglAoKLnpiSWrg\u0026q=85\u0026s=9b42068ec92bdc8c9edbfd0a097c1103\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.intelligence-management-platform.com#website\",\"name\":\"IMP Docs\",\"url\":\"https://docs.intelligence-management-platform.com\",\"publisher\":{\"@id\":\"https://docs.intelligence-management-platform.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.intelligence-management-platform.com/self-hosting/database#webpage\",\"url\":\"https://docs.intelligence-management-platform.com/self-hosting/database\",\"name\":\"Database\",\"description\":\"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\",\"dateModified\":\"2026-07-24T14:45:55.202Z\",\"isPartOf\":{\"@id\":\"https://docs.intelligence-management-platform.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.intelligence-management-platform.com/self-hosting/database#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.intelligence-management-platform.com/self-hosting/database#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Operate\",\"item\":\"https://docs.intelligence-management-platform.com/self-hosting/containers\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Database\",\"item\":\"https://docs.intelligence-management-platform.com/self-hosting/database\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.intelligence-management-platform.com/self-hosting/database#article\",\"headline\":\"Database\",\"name\":\"Database\",\"description\":\"How IMP manages its Postgres schema: the no-migration-framework model, idempotent initdb, first-boot bootstrap, and backup strategy.\",\"url\":\"https://docs.intelligence-management-platform.com/self-hosting/database\",\"mainEntityOfPage\":{\"@id\":\"https://docs.intelligence-management-platform.com/self-hosting/database#webpage\"},\"dateModified\":\"2026-07-24T14:45:55.202Z\",\"publisher\":{\"@id\":\"https://docs.intelligence-management-platform.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.intelligence-management-platform.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"IMP Docs\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"IMP Docs","nav":{"global":null,"tabs":[{"tab":"Get Started","icon":"rocket","pages":[{"title":"Get Started","href":""}]},{"tab":"User Guide","icon":"message-square","pages":[{"title":"User Guide","href":"/user-guide/chat/overview"}]},{"tab":"Building","icon":"hammer","pages":[{"title":"Building","href":"/building/agents/overview"}]},{"tab":"Administration","icon":"shield","pages":[{"title":"Administration","href":"/administration/users-access/overview"}]},{"tab":"Self-Hosting","icon":"server","groups":[{"group":"Deploy","pages":[{"title":"Architecture","icon":"network","href":"/self-hosting/architecture"},{"title":"Requirements","icon":"list-checks","href":"/self-hosting/requirements"},{"title":"Quickstart","icon":"play","href":"/self-hosting/quickstart"}]},{"group":"Services","pages":[{"title":"Postgres","icon":"database","href":"/self-hosting/services/postgres"},{"title":"Redis","icon":"layers","href":"/self-hosting/services/redis"},{"title":"S3-compatible storage","icon":"hard-drive","href":"/self-hosting/services/s3-storage"},{"title":"LiteLLM proxy","icon":"cpu","href":"/self-hosting/services/litellm"},{"title":"Whisper transcription server","icon":"mic","href":"/self-hosting/services/whisper"},{"title":"SMTP and authentication","icon":"lock","href":"/self-hosting/services/smtp-and-auth"},{"title":"Observability","icon":"activity","href":"/self-hosting/services/observability"}]},{"group":"Operate","pages":[{"title":"Containers","icon":"box","href":"/self-hosting/containers"},{"title":"Environment variables","icon":"settings","href":"/self-hosting/environment-variables"},{"title":"Branding","description":"How to supply a client favicon, logo, and app name for a self-hosted IMP deployment.","icon":"paintbrush","href":"/self-hosting/branding"},{"title":"Database","icon":"database","href":"/self-hosting/database"},{"title":"Operations","description":"Server/worker architecture, scaling workers, queue tuning, pm2 in containers, upgrades, and Dokploy network configuration.","icon":"settings-2","href":"/self-hosting/operations"},{"title":"Troubleshooting","icon":"circle-help","href":"/self-hosting/troubleshooting"}]}]},{"tab":"Developers","icon":"code","pages":[{"title":"Developers","href":"/developers/setup"}]},{"tab":"API Reference","icon":"braces","pages":[{"title":"API Reference","href":"/api-reference/rest/introduction"}]},{"tab":"Changelog","icon":"history","pages":[{"title":"Changelog","href":"/changelog"}]}]},"basePath":"","title":"Database - IMP Docs","buildId":"dpl_42LwxxU1kGN114H4XzwGYXa9ZDah","deploymentId":"dpl_42LwxxU1kGN114H4XzwGYXa9ZDah","dynamics":[],"chunks":[]}