Native DDL and managed workflows across Neki shards
A statement that changes a large or busy table can hold locks, rewrite existing
rows, build an index, generate large volumes of write-ahead log (WAL), and
consume substantial database resources. These effects can increase query
latency or stop application traffic.Sharding adds another requirement: every shard must end with the same table definition. Applying a change independently on each shard makes progress and failure difficult to track. It can also leave some shards on the old definition and others on the new definition.Neki supports both native DDL and managed DDL. Native DDL means issuing a supported statement such as ALTER TABLE through a router. Neki sends the statement to every managed shard, where Postgres executes it immediately. Native DDL has no workflow record, progress tracking, readiness gate, or explicit completion step.After native DDL commits, the change is committed across the managed shards,
but another router may not have refreshed its local schema view yet. The router
that accepts the DDL emits a notice containing the exact
__neki.wait_for_ddl(schema_version, cluster_version) call for that change.
Run that call before sending dependent SQL through other router instances:
The wait completes when the schema change is visible on every router. A notice
or warning about router visibility does not mean that the DDL transaction
failed; read the notice and use the supplied wait call to establish the
cluster-wide visibility barrier.
During Platform Preview, a shard added later receives existing publications
with the rest of the schema. Subscriptions are not part of that schema, so a
shard added later does not receive them. Contact PlanetScale Support before
combining Postgres logical replication with shard lifecycle changes.
Managed DDL uses a workflow. The workflow records the requested DDL, tracks progress on every managed shard, waits until the change is ready everywhere, and gives you explicit control over completion and cleanup.
Neki’s managed DDL supports two execution paths.Online DDL is designed for changes that would be disruptive when applied to the live table. Examples include changes that rewrite many rows and index creation on a large table. Neki builds an updated shadow table in the background while the application continues to use the original table.Direct DDL sends the change directly to Postgres in a transaction. This path is appropriate for statements that do not need a table copy, and it is the only managed path for statements that the shadow-table process cannot carry. Examples include creating or dropping a table and changes to types, sequences, and views.Neki examines the requested DDL and selects the appropriate path. You can also choose direct execution for an online-compatible change when applying the change directly is preferable. A request that combines incompatible online and direct work may need to be split into separate workflows.Both paths use the same managed workflow. Direct DDL receives the same progress tracking, readiness gate, explicit completion, retry handling, and multi-shard coordination as Online DDL.
Online DDL keeps the live table available while Neki builds its replacement:
It creates a shadow table beside the live table.
It applies the requested DDL to the shadow table.
It copies the existing rows from the live table to the shadow table in batches, using a sequence of transactions instead of one transaction for the entire copy.
Meanwhile, it streams ongoing inserts, updates, and deletes to the shadow table.
It keeps applying changes until the shadow table is caught up and ready for cutover.
The application continues to read and write the original table during these steps. Copying rows and catching up can take a long time, but the batched work limits the size and duration of each transaction.Cutover is the short final step. Neki first asks routers to buffer new queries for the affected table. Neki then locks the table, applies the final streamed changes, and swaps the original and shadow tables in one Postgres transaction. When the transaction commits, the new table definition is live under the original table name. Buffered queries then continue against the new table.If Neki cannot acquire the lock within the cutover timeout, it backs off and retries. Application traffic continues between attempts.
Direct DDL does not create a shadow table or copy rows. The shard records that it is ready, then waits for you to complete the workflow. At completion, Postgres applies the DDL in a transaction.Direct execution can require locks on the live table. The safety of this path therefore depends on the requested operation and the table workload. Neki uses it for statements that are best handled directly, and you can select it deliberately for changes that are safe to run in place.
A Neki database has one logical table definition across its managed shards. Some shards store rows for a table. Other shards keep the table definition but do not store rows for that table.For most online-compatible table changes:
Data-bearing shards copy and catch up a shadow table with Online DDL.
Schema-only shards wait to apply the same change directly.
For a direct schema change, every managed shard waits on the direct path.The workflow reports each shard’s progress and does not become ready to complete until every shard is ready:
An online shard is ready when its shadow table is copied and caught up.
A direct shard is ready when it is waiting to apply its transaction.
When every shard is ready, complete the workflow once. Neki tells each shard to cut over or apply its direct DDL.
Each shard commits its own Postgres transaction. Completion is coordinated, but it is not one atomic transaction across the whole Neki database. In normal operation, shards finish within seconds of one another, although failures can extend that interval.If one shard completes and another shard fails, Neki preserves the workflow and its per-shard status. The safe recovery direction is forward: clean up the failed attempt, reissue the workflow, then complete the remaining shards so every shard reaches the same table definition.
Creating the workflow records the DDL and starts the requested work on every managed shard. Status reports show overall progress and per-shard progress.Create a workflow from any Postgres client connected through a Neki router.
Double the single quotes inside the DDL string:
SELECT *FROM __neki.online_ddl_create( 'add-refund-state', 'orders_db', 'ALTER TABLE public.orders ADD COLUMN refund_state text NOT NULL DEFAULT ''none''', '');
The arguments are the workflow name, database name, DDL, and migration ID. An
empty migration ID tells Neki to generate one. The function returns the
workflow name and migration ID.Check the aggregate and per-shard status:
Wait until every shard reports ddl_status: "running",
current_readiness: true, and controller_state: "running". A
postgres_error means Neki could not read that shard’s state.Reissuing Create for an interrupted workflow can restore missing controllers and resume work from persisted state. Depending on where the interruption occurred, a shard may resume or restart its copy and streaming work. A failed attempt must be cleaned up before it can restart.
Completion is a separate, explicit action. Neki first verifies that every shard is ready and that no shard has failed. Online shards then cut over, and direct shards apply their DDL.
Repeated completion requests are safe. A shard that has already completed does not apply the change again. An unfinished shard continues toward the requested end state.
Cancel abandons the workflow before completion. In the normal path, Neki marks
each shard cancelled, removes its Online DDL artifacts, and deletes the
workflow record only after every shard reaches a safe final state.
Cancellation is rejected while a shard is actively cutting over because its
final table state is not yet known. Wait for cutover to settle, inspect
online_ddl_status, and retry Cancel.If some shards completed while others cancelled, Neki retains the workflow
record instead of hiding the schema skew. Reissue Create with the stored
configuration, allow the remaining shards to become ready, and Complete the
workflow so every shard converges on the new definition. Do not run blind
artifact cleanup across a mixed final state.
Cleanup is a separate action. After a successful complete, it drops the retained original table and the remaining Online DDL artifacts, then removes the workflow record when every shard has completed.
After a failed shard, cleanup removes that shard’s artifacts so you can reissue
Create. Neki keeps the workflow in that case. Normal cancellation performs its
own cleanup; do not follow a successful Cancel with a separate Cleanup.If cancellation or cleanup is interrupted, reissuing the operation is safe. Neki uses persisted workflow and per-shard state to resume, retry, or reject an action that would conflict with the recorded outcome.
Use native DDL when the change is safe to execute immediately and does not need workflow tracking or an explicit completion gate.Use managed Online DDL when direct execution could block traffic, rewrite a large live table, or build an index aggressively on the serving table.Use managed direct DDL when the statement cannot use the shadow-table process, when no copy is needed, or when you want workflow coordination for a change that is safe to run in place.Common single-table ALTER TABLE changes can use the online path, including
adding or dropping columns, changing a column type, adding or dropping
constraints, and adding an index. CREATE INDEX and DROP INDEX also use
the online path. Do not include CONCURRENTLY when creating an index through
Online DDL.Statements that do not need a shadow-table copy use the managed direct path.
These include CREATE TABLE, DROP TABLE, and operations on types, sequences,
and views. A table change can also be forced onto the direct path by passing
'{"applyDirect": true}' as the fifth argument to
online_ddl_create.Each workflow must resolve to one affected table and one execution category.
Split changes across workflows when they affect multiple tables or combine
online and direct work. Changing a table’s shard key or primary routing index
is a data-movement operation; use a resharding workflow instead.
{"docsConfig":{"theme":"aspen","$schema":"https://mintlify.com/docs.json","name":"PlanetScale","description":"PlanetScale is a relational database platform for Vitess, Neki, and Postgres that gives you scale, performance, and reliability without sacrificing developer experience.","colors":{"primary":"#0e73cc","light":"#47b7f8","dark":"#f15817"},"logo":{"light":"https://mintcdn.com/planetscale-2/xUilVHToUFALai8a/logo/light.png?fit=max\u0026auto=format\u0026n=xUilVHToUFALai8a\u0026q=85\u0026s=cccd3c9fc813c01b899ab7af15a115b1","dark":"https://mintcdn.com/planetscale-2/xUilVHToUFALai8a/logo/dark.png?fit=max\u0026auto=format\u0026n=xUilVHToUFALai8a\u0026q=85\u0026s=4153888dc0ef54ddc3464738a2d7ee6e","href":"https://planetscale.com"},"favicon":"https://mintcdn.com/planetscale-2/DJh9Bv1aUZHTVDnK/favicon.svg?fit=max\u0026auto=format\u0026n=DJh9Bv1aUZHTVDnK\u0026q=85\u0026s=cc6ec9d8d0deb3450719bb4b5b6df73a","background":{"color":{"light":"#fafafa","dark":"#111111"}},"navbar":{"links":[{"href":"https://auth.planetscale.com/sign-in","label":"Log in"},{"href":"https://auth.planetscale.com/sign-up","label":"Get started"}],"primary":{"type":"button","label":"Get in touch","href":"https://planetscale.com/contact"}},"footer":{"socials":{"x":"https://twitter.com/planetscale","github":"https://github.com/planetscale","linkedin":"https://www.linkedin.com/company/planetscale","youtube":"https://www.youtube.com/c/PlanetScale","discord":"https://pscale.link/community","facebook":"https://www.facebook.com/planetscaledata"}},"seo":{"metatags":{"canonical":"https://planetscale.com/docs"}},"fonts":{"heading":{"family":"Inter"},"body":{"family":"Inter"}},"integrations":{"segment":{"key":"9Ujczlrndco2w8fcFAakL0FT4bsJCCh3"}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":false},"navigation":{"global":{"anchors":[{"anchor":"Blog","icon":"newspaper","href":"https://planetscale.com/blog"},{"anchor":"Contact Us","icon":"headset","href":"https://planetscale.com/contact"},{"anchor":"Status","icon":"signal","href":"https://www.planetscalestatus.com/"},{"anchor":"Benchmarks","icon":"chart-line","href":"https://planetscale.com/benchmarks"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"planetscale-2","hasAudioNarration":false,"actualSubdomain":"planetscale-2","customDomains":["planetscale.com"],"gitSource":{"type":"github","owner":"planetscale","repo":"www","deployBranch":"main","contentDirectory":"content/mintlify/docs","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6ae4bbcf6d3c0060a25eeaab","collectionId":"049ef4be-45cb-4471-af55-3e8b42112ffe","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6ae4bbcf6d3c0060a25eeaab"},"entitlements":{"AI_CHAT":{"status":"ENABLED"},"CONTEXTUAL_FEEDBACK":{"status":"ENABLED"},"CODE_SNIPPET_FEEDBACK":{"status":"ENABLED"},"WEB_MCP":{"status":"ENABLED"},"NARRATION":{"status":"ENABLED"}},"buildId":"6ae4cefc4c4a3f4f5e4b3a5b","clientVersion":"0.0.4043","searchFilterCounts":[{"language":"default","tag":"Platform","count":288},{"language":"default","tag":"API Reference","count":268},{"language":"default","tag":"Vitess","count":184},{"language":"default","tag":"Postgres","count":108},{"language":"default","tag":"General API endpoints","count":97},{"language":"default","tag":"Neki","count":58},{"language":"default","tag":"Guides","count":58},{"language":"default","tag":"Vitess API endpoints","count":56},{"language":"default","tag":"Postgres API endpoints","count":51},{"language":"default","tag":"Neki API endpoints","count":50}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableAskAiSearchBar":true,"deflection":{"enabled":true,"type":"link","url":"https://planetscale.com/contact?initial=support"}},"basePath":"/docs","hasChatPermissions":true,"hasWebMcpPermissions":true,"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":"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":"byok-sep-25","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":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","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}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"#content-container{column-gap:2rem}.nav-tabs{column-gap:.5em}.nav-tabs-item{padding:0 8px}.eyebrow,.light #navigation-items .text-gray-700,.nav-tabs a{color:#616161}#navigation-items .text-primary,#topbar-cta-button .text-white,#topbar-cta-button svg,.nav-tabs a.text-primary{color:#1a1a1a}.nav-tabs a.text-primary .bg-primary{background-color:#1a1a1a;left:0}.dark .nav-tabs a[href='/docs/vitess'i].text-primary,.nav-tabs a[href='/docs/vitess'i].text-primary{color:#f15817}.dark .nav-tabs a[href='/docs/vitess'i].text-primary .bg-primary,.nav-tabs a[href='/docs/vitess'i].text-primary .bg-primary{background-color:#f15817}.nav-tabs a[href='/docs/postgres'i].text-primary{color:#0e73cc}.nav-tabs a[href='/docs/postgres'i].text-primary .bg-primary{background-color:#0e73cc}.nav-tabs a[href='/docs/neki'i].text-primary{color:#8f7200}.nav-tabs a[href='/docs/neki'i].text-primary .bg-primary{background-color:#8f7200}.dark .nav-tabs a{color:#a1a1a1}.dark #navigation-items .text-primary,.dark .nav-tabs a.text-primary{color:#fafafa}.dark .nav-tabs a.text-primary .bg-primary{background-color:#fafafa}.dark .nav-tabs a[href='/docs/postgres'i].text-primary{color:#47b7f8}.dark .nav-tabs a[href='/docs/postgres'i].text-primary .bg-primary{background-color:#47b7f8}.dark .nav-tabs a[href='/docs/neki'i].text-primary{color:#fbca00}.dark .nav-tabs a[href='/docs/neki'i].text-primary .bg-primary{background-color:#fbca00}.prose:is(.dark *){color:#c1c1c1}.prose :where(a):not(:where([class~='not-prose'], [class~='not-prose'] *)){color:#0e73cc;font-weight:500}.dark .prose :where(a):not(:where(.not-prose, .not-prose *)){color:#47b7f8}.dark .eyebrow{color:#a1a1a1}@media (min-width:1024px){#content-container{padding-top:2rem;padding-right:2rem;padding-left:2.5rem}}#topbar-cta-button a>span{background-color:#fbca00}.group:hover span{opacity:1!important}.bg-primary\\/10{background-color:rgba(129,129,129,.1)}.dark .bg-primary\\/10{background-color:rgba(255,255,255,.1)}body[data-current-path^='/vitess'] svg.bg-primary{background-color:#f15817}body[data-current-path^='/vitess'] .border-primary{border-color:#f15817}body[data-current-path^='/vitess'] #table-of-contents-content .text-primary,body[data-current-path^='/vitess'] .eyebrow{color:#f15817}body[data-current-path^='/vitess'] .card-group a:hover{border-color:#f15817!important}body[data-current-path^='/postgres'] .eyebrow{color:#0e73cc}.dark body[data-current-path^='/postgres'] .eyebrow{color:#47b7f8}body[data-current-path^='/neki'] svg.bg-primary{background-color:#8f7200}body[data-current-path^='/neki'] [data-component-part=card-icon]{background-color:#fbca00}body[data-current-path^='/neki'] [data-component-part=card-icon] svg.bg-primary{background-color:#1a1a1a;transform:scale(.7);transform-origin:center}body[data-current-path^='/neki'] .border-primary{border-color:#8f7200}body[data-current-path^='/neki'] #table-of-contents-content .text-primary{color:#1a1a1a;background-color:transparent;border-color:#fbca00}body[data-current-path^='/neki'] .eyebrow{display:inline-flex;align-items:center;width:fit-content;height:auto;min-height:1.25rem;padding:0 .375rem;color:#1a1a1a;background-color:#fbca00}body[data-current-path^='/neki'] .eyebrow:empty,body[data-current-path^='/neki'] .eyebrow[data-empty]{display:none}.dark body[data-current-path^='/neki'] .card-group .card:hover,body[data-current-path^='/neki'] .card-group .card:hover{--primary:251 202 0;--primary-light:251 202 0;border-color:#fbca00!important}.dark body[data-current-path^='/neki'] [data-component-part=card-icon],.dark body[data-current-path^='/neki'] svg.bg-primary{background-color:#fbca00}.dark body[data-current-path^='/neki'] [data-component-part=card-icon] svg.bg-primary{background-color:#1a1a1a}.dark body[data-current-path^='/neki'] .border-primary{border-color:#fbca00}.dark body[data-current-path^='/neki'] #table-of-contents-content .text-primary{color:#fafafa;background-color:transparent;border-color:#fbca00}.dark body[data-current-path^='/neki'] .eyebrow{color:#1a1a1a;background-color:#fbca00}footer div:last-child{display:none}#header,#pagination a,[data-component-part=card-content-container],[data-component-part=frame-caption]{text-wrap:balance}.step:last-of-type [data-component-part=step-line]{opacity:0}"}],"page":{"pagePath":"neki/schema-changes","slug":"/neki/schema-changes","pageMetadata":{"title":"Schema changes","description":"Native DDL and managed workflows across Neki shards","og:image":"images/og/neki/schema-changes.png","href":"/neki/schema-changes"},"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: \"Native DDL and managed workflows across Neki shards\"\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,Frame,Heading,OptimizedImage,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Frame)_missingMdxReference(`Frame`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!OptimizedImage)_missingMdxReference(`OptimizedImage`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`A statement that changes a large or busy table can hold locks, rewrite existing\nrows, build an index, generate large volumes of write-ahead log (WAL), and\nconsume substantial database resources. These effects can increase query\nlatency or stop application traffic.`}),`\n`,_jsx(_components.p,{children:`Sharding adds another requirement: every shard must end with the same table definition. Applying a change independently on each shard makes progress and failure difficult to track. It can also leave some shards on the old definition and others on the new definition.`}),`\n`,_jsxs(_components.p,{children:[`Neki supports both native DDL and managed DDL. Native DDL means issuing a supported statement such as `,_jsx(_components.code,{children:`ALTER TABLE`}),` through a router. Neki sends the statement to every managed shard, where Postgres executes it immediately. Native DDL has no workflow record, progress tracking, readiness gate, or explicit completion step.`]}),`\n`,_jsxs(_components.p,{children:[`After native DDL commits, the change is committed across the managed shards,\nbut another router may not have refreshed its local schema view yet. The router\nthat accepts the DDL emits a notice containing the exact\n`,_jsx(_components.code,{children:`__neki.wait_for_ddl(schema_version, cluster_version)`}),` call for that change.\nRun that call before sending dependent SQL through other router instances:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`wait_for_ddl`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`schema_version`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`\u003c`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`cluster_version`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:`>`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The wait completes when the schema change is visible on every router. A notice\nor warning about router visibility does not mean that the DDL transaction\nfailed; read the notice and use the supplied wait call to establish the\ncluster-wide visibility barrier.`}),`\n`,_jsx(Warning,{children:_jsx(_components.p,{children:`During Platform Preview, a shard added later receives existing publications\nwith the rest of the schema. Subscriptions are not part of that schema, so a\nshard added later does not receive them. Contact PlanetScale Support before\ncombining Postgres logical replication with shard lifecycle changes.`})}),`\n`,_jsx(_components.p,{children:`Managed DDL uses a workflow. The workflow records the requested DDL, tracks progress on every managed shard, waits until the change is ready everywhere, and gives you explicit control over completion and cleanup.`}),`\n`,_jsx(Heading,{level:`2`,id:`online-and-direct-schema-changes`,children:`Online and direct schema changes`}),`\n`,_jsx(_components.p,{children:`Neki’s managed DDL supports two execution paths.`}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Online DDL`}),` is designed for changes that would be disruptive when applied to the live table. Examples include changes that rewrite many rows and index creation on a large table. Neki builds an updated shadow table in the background while the application continues to use the original table.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Direct DDL`}),` sends the change directly to Postgres in a transaction. This path is appropriate for statements that do not need a table copy, and it is the only managed path for statements that the shadow-table process cannot carry. Examples include creating or dropping a table and changes to types, sequences, and views.`]}),`\n`,_jsx(_components.p,{children:`Neki examines the requested DDL and selects the appropriate path. You can also choose direct execution for an online-compatible change when applying the change directly is preferable. A request that combines incompatible online and direct work may need to be split into separate workflows.`}),`\n`,_jsx(_components.p,{children:`Both paths use the same managed workflow. Direct DDL receives the same progress tracking, readiness gate, explicit completion, retry handling, and multi-shard coordination as Online DDL.`}),`\n`,_jsx(Heading,{level:`2`,id:`how-online-ddl-works`,children:`How Online DDL works`}),`\n`,_jsx(_components.p,{children:`Online DDL keeps the live table available while Neki builds its replacement:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsx(_components.li,{children:`It creates a shadow table beside the live table.`}),`\n`,_jsx(_components.li,{children:`It applies the requested DDL to the shadow table.`}),`\n`,_jsx(_components.li,{children:`It copies the existing rows from the live table to the shadow table in batches, using a sequence of transactions instead of one transaction for the entire copy.`}),`\n`,_jsx(_components.li,{children:`Meanwhile, it streams ongoing inserts, updates, and deletes to the shadow table.`}),`\n`,_jsx(_components.li,{children:`It keeps applying changes until the shadow table is caught up and ready for cutover.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`The application continues to read and write the original table during these steps. Copying rows and catching up can take a long time, but the batched work limits the size and duration of each transaction.`}),`\n`,_jsx(_components.p,{children:`Cutover is the short final step. Neki first asks routers to buffer new queries for the affected table. Neki then locks the table, applies the final streamed changes, and swaps the original and shadow tables in one Postgres transaction. When the transaction commits, the new table definition is live under the original table name. Buffered queries then continue against the new table.`}),`\n`,_jsx(_components.p,{children:`If Neki cannot acquire the lock within the cutover timeout, it backs off and retries. Application traffic continues between attempts.`}),`\n`,_jsx(Heading,{level:`2`,id:`how-direct-ddl-works`,children:`How direct DDL works`}),`\n`,_jsx(_components.p,{children:`Direct DDL does not create a shadow table or copy rows. The shard records that it is ready, then waits for you to complete the workflow. At completion, Postgres applies the DDL in a transaction.`}),`\n`,_jsx(_components.p,{children:`Direct execution can require locks on the live table. The safety of this path therefore depends on the requested operation and the table workload. Neki uses it for statements that are best handled directly, and you can select it deliberately for changes that are safe to run in place.`}),`\n`,_jsx(Heading,{level:`2`,id:`one-workflow-across-all-shards`,children:`One workflow across all shards`}),`\n`,_jsx(_components.p,{children:`A Neki database has one logical table definition across its managed shards. Some shards store rows for a table. Other shards keep the table definition but do not store rows for that table.`}),`\n`,_jsx(_components.p,{children:`For most online-compatible table changes:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`Data-bearing shards copy and catch up a shadow table with Online DDL.`}),`\n`,_jsx(_components.li,{children:`Schema-only shards wait to apply the same change directly.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`For a direct schema change, every managed shard waits on the direct path.`}),`\n`,_jsx(_components.p,{children:`The workflow reports each shard’s progress and does not become ready to complete until every shard is ready:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:`An online shard is ready when its shadow table is copied and caught up.`}),`\n`,_jsx(_components.li,{children:`A direct shard is ready when it is waiting to apply its transaction.`}),`\n`]}),`\n`,_jsx(_components.p,{children:`When every shard is ready, complete the workflow once. Neki tells each shard to cut over or apply its direct DDL.`}),`\n`,_jsxs(Frame,{children:[_jsx(OptimizedImage,{src:`https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=98241d0d143e60b6c5a7462922d507df`,className:`mint-block dark:mint-hidden`,alt:`A schema-change workflow prepares and catches up shadow tables on data-bearing shards while schema-only shards wait for direct DDL. After every shard reports ready, each shard commits independently. Online shards atomically swap tables and schema-only shards apply direct DDL before the Postgres schema converges across managed shards.`,\"data-og-width\":`2984`,width:`2984`,\"data-og-height\":`1579`,height:`1579`,\"data-path\":`neki/schema-changes/online-change.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=280\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=c3c0306140b53825b3a8760806111add 280w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=560\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=086f6e91a92eff867d162d334b8f15a5 560w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=840\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=f7ab928998768d31b305f44e4ccd3e27 840w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=1100\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=98646549037def86413b96716cc4f175 1100w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=1650\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=21e894faffd674350b24d4711026b7a2 1650w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change.png?w=2500\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=a06886a462f14a56a8277361cacc86b0 2500w`}),_jsx(OptimizedImage,{src:`https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=2ee9c6b589fbab31e3b2a20ba1b16b10`,className:`mint-hidden dark:mint-block`,alt:`A schema-change workflow prepares and catches up shadow tables on data-bearing shards while schema-only shards wait for direct DDL. After every shard reports ready, each shard commits independently. Online shards atomically swap tables and schema-only shards apply direct DDL before the Postgres schema converges across managed shards.`,\"data-og-width\":`2984`,width:`2984`,\"data-og-height\":`1579`,height:`1579`,\"data-path\":`neki/schema-changes/online-change-darkmode.png`,\"data-optimize\":`true`,\"data-opv\":`3`,srcset:`https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=280\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=4032fccc11895baa1bbfac2d2e22b66e 280w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=560\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=0f0ac3ea2560aca38915eac5845f2775 560w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=840\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=157cd273acdbbc2148900c3ef39d578e 840w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=1100\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=a712093fd71f5f0d3aa06312cb09f15d 1100w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=1650\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=9e4ea9b749011dbbc4d2e17172f4c8cb 1650w, https://mintcdn.com/planetscale-2/6i1lJ6cNfB-VSsaH/neki/schema-changes/online-change-darkmode.png?w=2500\u0026fit=max\u0026auto=format\u0026n=6i1lJ6cNfB-VSsaH\u0026q=85\u0026s=4ecd09ccbab7ce425d033da45485fe56 2500w`})]}),`\n`,_jsx(_components.p,{children:`Each shard commits its own Postgres transaction. Completion is coordinated, but it is not one atomic transaction across the whole Neki database. In normal operation, shards finish within seconds of one another, although failures can extend that interval.`}),`\n`,_jsx(_components.p,{children:`If one shard completes and another shard fails, Neki preserves the workflow and its per-shard status. The safe recovery direction is forward: clean up the failed attempt, reissue the workflow, then complete the remaining shards so every shard reaches the same table definition.`}),`\n`,_jsx(Heading,{level:`2`,id:`managing-the-workflow`,children:`Managing the workflow`}),`\n`,_jsx(_components.p,{children:`A schema-change workflow has a small lifecycle.`}),`\n`,_jsx(Heading,{level:`3`,id:`create-and-track`,children:`Create and track`}),`\n`,_jsx(_components.p,{children:`Creating the workflow records the DDL and starts the requested work on every managed shard. Status reports show overall progress and per-shard progress.`}),`\n`,_jsx(_components.p,{children:`Create a workflow from any Postgres client connected through a Neki router.\nDouble the single quotes inside the DDL string:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`7`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`7`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` *`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`FROM`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_create`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'orders_db'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'ALTER TABLE public.orders ADD COLUMN refund_state text NOT NULL DEFAULT ''none'''`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ''`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`The arguments are the workflow name, database name, DDL, and migration ID. An\nempty migration ID tells Neki to generate one. The function returns the\nworkflow name and migration ID.`}),`\n`,_jsx(_components.p,{children:`Check the aggregate and per-shard status:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`2`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`2`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` workflow, ddl, `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`status`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, jsonb_pretty(status_by_shard)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`FROM`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_status`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Wait until every shard reports `,_jsx(_components.code,{children:`ddl_status: \"running\"`}),`,\n`,_jsx(_components.code,{children:`current_readiness: true`}),`, and `,_jsx(_components.code,{children:`controller_state: \"running\"`}),`. A\n`,_jsx(_components.code,{children:`postgres_error`}),` means Neki could not read that shard’s state.`]}),`\n`,_jsx(_components.p,{children:`Reissuing Create for an interrupted workflow can restore missing controllers and resume work from persisted state. Depending on where the interruption occurred, a shard may resume or restart its copy and streaming work. A failed attempt must be cleaned up before it can restart.`}),`\n`,_jsx(Heading,{level:`3`,id:`complete`,children:`Complete`}),`\n`,_jsx(_components.p,{children:`Completion is a separate, explicit action. Neki first verifies that every shard is ready and that no shard has failed. Online shards then cut over, and direct shards apply their DDL.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`workflow_complete`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:` workflow, `}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`status`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`, jsonb_pretty(status_by_shard)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`FROM`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_status`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Repeated completion requests are safe. A shard that has already completed does not apply the change again. An unfinished shard continues toward the requested end state.`}),`\n`,_jsx(Heading,{level:`3`,id:`cancel`,children:`Cancel`}),`\n`,_jsx(_components.p,{children:`Cancel abandons the workflow before completion. In the normal path, Neki marks\neach shard cancelled, removes its Online DDL artifacts, and deletes the\nworkflow record only after every shard reaches a safe final state.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`workflow_cancel`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Cancellation is rejected while a shard is actively cutting over because its\nfinal table state is not yet known. Wait for cutover to settle, inspect\n`,_jsx(_components.code,{children:`online_ddl_status`}),`, and retry Cancel.`]}),`\n`,_jsx(_components.p,{children:`If some shards completed while others cancelled, Neki retains the workflow\nrecord instead of hiding the schema skew. Reissue Create with the stored\nconfiguration, allow the remaining shards to become ready, and Complete the\nworkflow so every shard converges on the new definition. Do not run blind\nartifact cleanup across a mixed final state.`}),`\n`,_jsx(Heading,{level:`3`,id:`clean-up`,children:`Clean up`}),`\n`,_jsx(_components.p,{children:`Cleanup is a separate action. After a successful complete, it drops the retained original table and the remaining Online DDL artifacts, then removes the workflow record when every shard has completed.`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`1`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`1`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_cleanup`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`After a failed shard, cleanup removes that shard’s artifacts so you can reissue\nCreate. Neki keeps the workflow in that case. Normal cancellation performs its\nown cleanup; do not follow a successful Cancel with a separate Cleanup.`}),`\n`,_jsx(_components.p,{children:`If cancellation or cleanup is interrupted, reissuing the operation is safe. Neki uses persisted workflow and per-shard state to resume, retry, or reject an action that would conflict with the recorded outcome.`}),`\n`,_jsx(Heading,{level:`3`,id:`retry-a-failed-shard`,children:`Retry a failed shard`}),`\n`,_jsx(_components.p,{children:`Clean up the failed attempt, then reissue Create with the stored workflow\nconfiguration:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`sql`,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:`sql`,children:_jsxs(_components.code,{language:`sql`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_cleanup`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`SELECT`}),_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#D4D4D4`},children:` *`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#CF222E`,\"--shiki-dark\":`#569CD6`},children:`FROM`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:` __neki`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`.`}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#D4D4D4`},children:`online_ddl_create`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` 'add-refund-state'`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ''`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ''`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:` ''`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`);`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`Completed shards do not apply the change again. After all shards become ready,\nrun `,_jsx(_components.code,{children:`workflow_complete`}),` and `,_jsx(_components.code,{children:`online_ddl_cleanup`}),` as above.`]}),`\n`,_jsx(Heading,{level:`2`,id:`choosing-a-path`,children:`Choosing a path`}),`\n`,_jsx(_components.p,{children:`Use native DDL when the change is safe to execute immediately and does not need workflow tracking or an explicit completion gate.`}),`\n`,_jsx(_components.p,{children:`Use managed Online DDL when direct execution could block traffic, rewrite a large live table, or build an index aggressively on the serving table.`}),`\n`,_jsx(_components.p,{children:`Use managed direct DDL when the statement cannot use the shadow-table process, when no copy is needed, or when you want workflow coordination for a change that is safe to run in place.`}),`\n`,_jsxs(_components.p,{children:[`Common single-table `,_jsx(_components.code,{children:`ALTER TABLE`}),` changes can use the online path, including\nadding or dropping columns, changing a column type, adding or dropping\nconstraints, and adding an index. `,_jsx(_components.code,{children:`CREATE INDEX`}),` and `,_jsx(_components.code,{children:`DROP INDEX`}),` also use\nthe online path. Do not include `,_jsx(_components.code,{children:`CONCURRENTLY`}),` when creating an index through\nOnline DDL.`]}),`\n`,_jsxs(_components.p,{children:[`Statements that do not need a shadow-table copy use the managed direct path.\nThese include `,_jsx(_components.code,{children:`CREATE TABLE`}),`, `,_jsx(_components.code,{children:`DROP TABLE`}),`, and operations on types, sequences,\nand views. A table change can also be forced onto the direct path by passing\n`,_jsx(_components.code,{children:`'{\"applyDirect\": true}'`}),` as the fifth argument to\n`,_jsx(_components.code,{children:`online_ddl_create`}),`.`]}),`\n`,_jsx(_components.p,{children:`Each workflow must resolve to one affected table and one execution category.\nSplit changes across workflows when they affect multiple tables or combine\nonline and direct work. Changing a table’s shard key or primary routing index\nis a data-movement operation; use a resharding workflow instead.`}),`\n`,_jsx(Heading,{level:`2`,id:`need-help`,children:`Need help?`}),`\n`,_jsxs(_components.p,{children:[`Get help from `,_jsx(_components.a,{href:`https://planetscale.com/contact?initial=support`,children:`the PlanetScale Support team`}),`, or join our\\xA0`,_jsx(_components.a,{href:`https://pscale.link/community`,children:`Discord community`}),` to see how others are using PlanetScale.`]})]})}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":"Schema changes","description":"Native DDL and managed workflows across Neki shards","og:image":"images/og/neki/schema-changes.png","href":"/neki/schema-changes"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Online and direct schema changes","slug":"online-and-direct-schema-changes","depth":2,"children":[]},{"title":"How Online DDL works","slug":"how-online-ddl-works","depth":2,"children":[]},{"title":"How direct DDL works","slug":"how-direct-ddl-works","depth":2,"children":[]},{"title":"One workflow across all shards","slug":"one-workflow-across-all-shards","depth":2,"children":[]},{"title":"Managing the workflow","slug":"managing-the-workflow","depth":2,"children":[{"title":"Create and track","slug":"create-and-track","depth":3,"children":[]},{"title":"Complete","slug":"complete","depth":3,"children":[]},{"title":"Cancel","slug":"cancel","depth":3,"children":[]},{"title":"Clean up","slug":"clean-up","depth":3,"children":[]},{"title":"Retry a failed shard","slug":"retry-a-failed-shard","depth":3,"children":[]}]},{"title":"Choosing a path","slug":"choosing-a-path","depth":2,"children":[]},{"title":"Need help?","slug":"need-help","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/planetscale-2/b155242ec3c4945e/custom.js"],"dynamicCss":".mint-block {\n display: block\n}\n.mint-hidden {\n display: none\n}\n.dark\\:mint-block:is(.dark *) {\n display: block\n}\n.dark\\:mint-hidden:is(.dark *) {\n display: none\n}","subdomain":"planetscale-2","siteName":"PlanetScale","title":"Schema changes - PlanetScale","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-07T18:11:36.551Z","originalFileLocation":"neki/schema-changes.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=\"Native DDL and managed workflows across Neki shards\">\u003cmeta data-mint-head name=\"application-name\" content=\"PlanetScale\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_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=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Schema changes - PlanetScale\">\u003cmeta data-mint-head property=\"og:description\" content=\"Native DDL and managed workflows across Neki shards\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"PlanetScale\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://planetscale.com/docs/neki/schema-changes\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://planetscale-2.mintlify.app/images/og/neki/schema-changes.png\">\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=\"Schema changes - PlanetScale\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Native DDL and managed workflows across Neki shards\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://planetscale-2.mintlify.app/images/og/neki/schema-changes.png\">\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=\"/docs/mintlify-assets/_mintlify/favicons/planetscale-2/_bFyi8IG4CeLblEd/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"PlanetScale\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#0e73cc\">\u003clink data-mint-head rel=\"canonical\" href=\"https://planetscale.com/docs/neki/schema-changes\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/neki/schema-changes.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://planetscale.com/#organization\",\"name\":\"PlanetScale\",\"url\":\"https://planetscale.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/planetscale-2/xUilVHToUFALai8a/logo/light.png?fit=max\u0026auto=format\u0026n=xUilVHToUFALai8a\u0026q=85\u0026s=cccd3c9fc813c01b899ab7af15a115b1\"}},{\"@type\":\"WebSite\",\"@id\":\"https://planetscale.com/docs#website\",\"name\":\"PlanetScale\",\"url\":\"https://planetscale.com/docs\",\"publisher\":{\"@id\":\"https://planetscale.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://planetscale.com/docs/neki/schema-changes#webpage\",\"url\":\"https://planetscale.com/docs/neki/schema-changes\",\"name\":\"Schema changes\",\"description\":\"Native DDL and managed workflows across Neki shards\",\"dateModified\":\"2026-10-07T18:11:36.551Z\",\"isPartOf\":{\"@id\":\"https://planetscale.com/docs#website\"},\"breadcrumb\":{\"@id\":\"https://planetscale.com/docs/neki/schema-changes#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://planetscale.com/docs/neki/schema-changes#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Architecture\",\"item\":\"https://planetscale.com/docs/neki/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Workflows\",\"item\":\"https://planetscale.com/docs/neki/data-migration\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Schema changes\",\"item\":\"https://planetscale.com/docs/neki/schema-changes\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://planetscale.com/docs/neki/schema-changes#article\",\"headline\":\"Schema changes\",\"name\":\"Schema changes\",\"description\":\"Native DDL and managed workflows across Neki shards\",\"url\":\"https://planetscale.com/docs/neki/schema-changes\",\"mainEntityOfPage\":{\"@id\":\"https://planetscale.com/docs/neki/schema-changes#webpage\"},\"image\":\"https://planetscale.com/docs/images/og/neki/schema-changes.png\",\"dateModified\":\"2026-10-07T18:11:36.551Z\",\"publisher\":{\"@id\":\"https://planetscale.com/#organization\"},\"isPartOf\":{\"@id\":\"https://planetscale.com/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"PlanetScale\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"PlanetScale","nav":{"global":{"anchors":[{"anchor":"Blog","icon":"newspaper","href":"https://planetscale.com/blog"},{"anchor":"Contact Us","icon":"headset","href":"https://planetscale.com/contact"},{"anchor":"Status","icon":"signal","href":"https://www.planetscalestatus.com/"},{"anchor":"Benchmarks","icon":"chart-line","href":"https://planetscale.com/benchmarks"}]},"tabs":[{"tab":"Platform","pages":[{"title":"Platform","href":""}]},{"tab":"Vitess","pages":[{"title":"Vitess","href":"/vitess"}]},{"tab":"Neki","groups":[{"group":" ","pages":[{"title":"Neki","href":"/neki"}]},{"group":"Architecture","pages":[{"group":"Foundations","pages":[{"title":"Overview","href":"/neki/overview"},{"title":"When to shard","href":"/neki/when-to-shard"},{"title":"Neki vs PlanetScale Postgres","href":"/neki/coming-from-postgres"},{"title":"Neki vs Vitess","href":"/neki/vitess-and-postgres"}]},{"group":"Core concepts","pages":[{"title":"Data topology","href":"/neki/data-topology"},{"title":"Query planning","href":"/neki/query-planning"},{"title":"Shard targeting and fanout","href":"/neki/shard-targeting-fanout"},{"title":"Transactions","href":"/neki/transactions"},{"title":"Reference tables and GSIs","href":"/neki/reference-tables-and-gsis"},{"title":"Replicator workflows","sidebarTitle":"Replicator","href":"/neki/replication"}]},{"group":"Workflows","pages":[{"title":"Data migration","description":"Table movement, resharding, verification, and traffic cutover","href":"/neki/data-migration"},{"title":"Schema changes","href":"/neki/schema-changes"}]},{"group":"Reference","pages":[{"title":"Platform preview limitations","description":"Postgres features and query shapes that Neki does not support during Platform Preview","href":"/neki/platform-preview-limitations"},{"title":"Neki terminology","sidebarTitle":"Terminology","href":"/neki/terminology"},{"title":"Neki error codes","sidebarTitle":"Error codes","href":"/neki/error-codes"},{"title":"Error hints and details","sidebarTitle":"Hints and details","href":"/neki/error-hints-and-details"},{"title":"EXPLAIN output reference","sidebarTitle":"EXPLAIN output","href":"/neki/explain-reference"},{"title":"Example schema","href":"/neki/example-schema"}]}]},{"group":"Pricing","pages":[{"title":"Neki pricing","sidebarTitle":"Pricing","href":"/neki/pricing"}]},{"group":"Platform","pages":[{"group":"Getting started","pages":[{"title":"Neki database dashboard","sidebarTitle":"Dashboard overview","href":"/neki/neki-dashboard"},{"title":"Neki quickstart","href":"/neki/tutorials/planetscale-quick-start-guide"},{"title":"Neki sharding quickstart","sidebarTitle":"Sharding quickstart","href":"/neki/tutorials/sharding-quick-start-guide"},{"title":"Neki best practices","sidebarTitle":"Best practices","href":"/neki/best-practices"}]},{"group":"Connecting","pages":[{"title":"Connect to Neki","sidebarTitle":"Overview","href":"/neki/connecting"},{"title":"Roles and credentials","href":"/neki/connecting/roles"},{"title":"PlanetScale Terraform provider","sidebarTitle":"Terraform provider","href":"/terraform"},{"group":"Private connections","pages":[{"title":"Connect privately with AWS PrivateLink","sidebarTitle":"AWS PrivateLink","href":"/neki/connecting/private-connections/aws-privatelink"},{"title":"Connect privately with GCP Private Service Connect","sidebarTitle":"GCP Private Service Connect","href":"/neki/connecting/private-connections/gcp-private-service-connect"}]},{"title":"Web console","href":"/neki/web-console"}]},{"group":"Configuration","pages":[{"title":"Cluster sizing","href":"/neki/cluster-configuration/cluster-sizing"},{"title":"Cluster configuration","href":"/neki/cluster-configuration"},{"title":"Configure Neki maintenance windows","sidebarTitle":"Maintenance windows","href":"/neki/cluster-configuration/maintenance-windows"},{"title":"Configuration parameters","sidebarTitle":"Parameters","href":"/neki/cluster-configuration/parameters"},{"title":"Database replicas","sidebarTitle":"Replicas","href":"/neki/replicas"},{"title":"Read-only replicas","sidebarTitle":"Read-only replicas","href":"/neki/read-only-replicas"}]},{"title":"Postgres extensions","sidebarTitle":"Extensions","href":"/neki/extensions"},{"group":"Migrate to Neki","pages":[{"title":"Import a Postgres database","sidebarTitle":"Import Postgres","href":"/neki/imports/postgres"},{"title":"Troubleshoot a Neki migration","sidebarTitle":"Migration troubleshooting","href":"/neki/imports/troubleshooting"}]},{"group":"Branching","pages":[{"title":"Branching","href":"/neki/branching"},{"title":"Development environments","href":"/neki/development-environments"}]},{"group":"Monitoring","pages":[{"title":"Monitor a Neki database","sidebarTitle":"Monitoring overview","href":"/neki/monitoring"},{"title":"Query Insights","href":"/neki/monitoring/query-insights"},{"title":"Anomalies","href":"/neki/monitoring/anomalies"},{"title":"Schema recommendations","href":"/neki/monitoring/schema-recommendations"},{"title":"Metrics","href":"/neki/monitoring/metrics"},{"title":"Logs","href":"/neki/monitoring/logs"},{"title":"Inspect live Neki connections","sidebarTitle":"Connections","href":"/neki/monitoring/connections"},{"title":"Prometheus metrics for PlanetScale Neki","sidebarTitle":"Prometheus metrics reference","href":"/neki/monitoring/prometheus-metrics-neki"}]},{"title":"Back up and restore","sidebarTitle":"Backups","href":"/neki/backups"}]},{"group":"Guides","pages":[{"group":"Frameworks and ORMs","pages":[{"title":"Connect a Node.js application to Neki","sidebarTitle":"Node.js","href":"/neki/guides/node"},{"title":"Connect Drizzle to Neki","sidebarTitle":"Drizzle","href":"/neki/guides/drizzle"},{"title":"Connect Kysely to Neki","sidebarTitle":"Kysely","href":"/neki/guides/kysely"},{"title":"Connect Prisma to Neki","sidebarTitle":"Prisma","href":"/neki/guides/prisma"},{"title":"Connect a Ruby on Rails application to Neki","sidebarTitle":"Ruby on Rails","href":"/neki/guides/rails"},{"title":"Connect a Django application to Neki","sidebarTitle":"Django","href":"/neki/guides/django"},{"title":"Connect a Laravel application to Neki","sidebarTitle":"Laravel","href":"/neki/guides/laravel"},{"title":"Connect a Bun application to Neki","sidebarTitle":"Bun","href":"/neki/guides/bun"},{"title":"Connect Cloudflare Workers to Neki","sidebarTitle":"Cloudflare Workers","href":"/neki/guides/cloudflare-workers"}]}]}]},{"tab":"Postgres","pages":[{"title":"Postgres","href":"/postgres"}]},{"tab":"API Reference","pages":[{"title":"API Reference","href":"/api/reference/getting-started-with-planetscale-api"}]},{"tab":"CLI Reference","pages":[{"title":"CLI Reference","href":"/cli"}]}]},"basePath":"","title":"Schema changes - PlanetScale","buildId":"dpl_4RHMRqtvdHvKgaEfTTjFqjzja3B6","deploymentId":"dpl_4RHMRqtvdHvKgaEfTTjFqjzja3B6","dynamics":["07c022d89b","a74be98ba7"],"chunks":["Frame-CSp1VigC.js","DynamicMarkdown-Dnt6YhtR.js","zoom-image-lightbox-CZTaVDTN.js","lightbox-handle-r17bVUz3.js"]}