Skip to content

chore: localize status migration work#14862

Merged
JessRynkar merged 17 commits intofeat/experimental-localize-metadata-uifrom
feat/experimental-localize-metadata-migration
Jan 14, 2026
Merged

chore: localize status migration work#14862
JessRynkar merged 17 commits intofeat/experimental-localize-metadata-uifrom
feat/experimental-localize-metadata-migration

Conversation

@JarrodMFlesch
Copy link
Contributor

@JarrodMFlesch JarrodMFlesch commented Dec 8, 2025

Adds migration logic.

1. Create blank migration file

payload migrate:create localize_status

2. Add the migration code

PostgreSQL / SQLite:

import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-postgres'
import { sql } from '@payloadcms/db-postgres'
import { localizeStatus } from 'payload/migrations'

export async function up({ db, payload }: MigrateUpArgs): Promise<void> {
  await localizeStatus.up({
    collectionSlug: 'posts', // 👈 Change to your collection
    db,
    payload,
    sql,
  })
}

export async function down({ db, payload }: MigrateDownArgs): Promise<void> {
  await localizeStatus.down({
    collectionSlug: 'posts',
    db,
    payload,
    sql,
  })
}

MongoDB:

import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-mongodb'
import { localizeStatus } from 'payload/migrations'

export async function up({ payload }: MigrateUpArgs): Promise<void> {
  await localizeStatus.up({
    collectionSlug: 'posts', // 👈 Change to your collection
    payload,
  })
}

export async function down({ payload }: MigrateDownArgs): Promise<void> {
  await localizeStatus.down({
    collectionSlug: 'posts',
    payload,
  })
}
Related PRs in this feature

@JarrodMFlesch JarrodMFlesch changed the title localize status migration work chore: localize status migration work Dec 8, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 8, 2025

📦 esbuild Bundle Analysis for payload

This analysis was generated by esbuild-bundle-analyzer. 🤖

Meta File Out File Size (raw) Note
packages/next/meta_index.json esbuild/index.js 935.55 KB 🆕 Added
packages/payload/meta_index.json esbuild/index.js 1.26 MB 🆕 Added
packages/payload/meta_shared.json esbuild/exports/shared.js 164.49 KB 🆕 Added
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 281.24 KB 🆕 Added
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.17 MB 🆕 Added
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 16.08 KB 🆕 Added
Largest paths These visualization shows top 20 largest paths in the bundle.

Meta file: packages/next/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████████▌ }}}$ 82.4%, 766.76 KB
dist/views/Version ${{\color{Goldenrod}{ █▎ }}}$ 5.4%, 50.51 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 16.48 KB
dist/views/Document ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 15.72 KB
dist/views/List ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 11.27 KB
dist/views/Root ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 9.03 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 6.16 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.03 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.53 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.46 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.81 KB
dist/views/Login ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.41 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 3.09 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.3%, 2.91 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.3%, 2.81 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.3%, 2.63 KB
dist/views/BrowseByFolder ${{\color{Goldenrod}{ }}}$ 0.3%, 2.56 KB
dist/views/CollectionFolders ${{\color{Goldenrod}{ }}}$ 0.3%, 2.44 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 2.40 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.2%, 1.94 KB
(other) ${{\color{Goldenrod}{ ████▍ }}}$ 17.6%, 164.12 KB

Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████████▊ }}}$ 67.1%, 842.06 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▉ }}}$ 3.5%, 43.58 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 37.85 KB
dist/versions/migrations ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 18.50 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.22 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.80 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.33 KB
dist/queues/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.05 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.04 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.21 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.53 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.35 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.74 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.65 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.50 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.27 KB
dist/collections/endpoints ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.21 KB
dist/config/sanitize.js ${{\color{Goldenrod}{ }}}$ 0.4%, 5.57 KB
dist/auth/strategies ${{\color{Goldenrod}{ }}}$ 0.4%, 5.50 KB
dist/auth/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 5.42 KB
(other) ${{\color{Goldenrod}{ ████████▏ }}}$ 32.9%, 413.29 KB

Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▋ }}}$ 78.9%, 126.93 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▌ }}}$ 6.3%, 10.21 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 2.51 KB
dist/auth/cookies.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 1.55 KB
dist/utilities/flattenTopLevelFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.42 KB
dist/fields/config ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.28 KB
dist/utilities/getVersionsConfig.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB
dist/utilities/flattenAllFields.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 943 B
dist/folders/utils ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 916 B
dist/utilities/unflatten.js ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 779 B
dist/utilities/sanitizeUserDataForEmail.js ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.4%, 651 B
dist/collections/config ${{\color{Goldenrod}{ }}}$ 0.4%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.3%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.3%, 413 B
dist/utilities/formatLabels.js ${{\color{Goldenrod}{ }}}$ 0.2%, 380 B
dist/utilities/appendUploadSelectFields.js ${{\color{Goldenrod}{ }}}$ 0.2%, 360 B
(other) ${{\color{Goldenrod}{ █████▎ }}}$ 21.1%, 34.02 KB

Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
dist/features/blocks ${{\color{Goldenrod}{ ███▏ }}}$ 12.6%, 35.02 KB
dist/lexical/plugins ${{\color{Goldenrod}{ ██▉ }}}$ 11.5%, 32.00 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▏ }}}$ 8.8%, 24.36 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 23.70 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▋ }}}$ 6.8%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▋ }}}$ 6.5%, 18.11 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 17.75 KB
dist/features/upload ${{\color{Goldenrod}{ █▎ }}}$ 5.0%, 13.77 KB
dist/features/textState ${{\color{Goldenrod}{ █ }}}$ 4.0%, 11.08 KB
dist/features/relationship ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 9.03 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 8.22 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.39 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 7.12 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 7.05 KB
dist/lexical/config ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.08 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.00 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 3.17 KB
dist/lexical/theme ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.62 KB
dist/features/indent ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.50 KB
(other) ${{\color{Goldenrod}{ █████████████████████▊ }}}$ 87.4%, 242.96 KB

Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████▍ }}}$ 49.5%, 572.94 KB
dist/elements/FolderView ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 29.29 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 27.20 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 16.91 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 16.39 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.78 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.48 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.26 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.15 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 13.69 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 10.33 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 9.03 KB
dist/providers/Folders ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.47 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/ListHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.90 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.81 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.73 KB
dist/views/CollectionFolder ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.38 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.31 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.99 KB
(other) ${{\color{Goldenrod}{ ████████████▋ }}}$ 50.5%, 583.79 KB

Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ █████ }}}$ 20.3%, 3.12 KB
../../node_modules ${{\color{Goldenrod}{ ████▎ }}}$ 17.2%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▍ }}}$ 9.9%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ ██▏ }}}$ 8.6%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▍ }}}$ 5.6%, 862 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █▎ }}}$ 5.3%, 812 B
dist/utilities/api.js ${{\color{Goldenrod}{ █▏ }}}$ 4.9%, 756 B
dist/utilities/getGlobalData.js ${{\color{Goldenrod}{ ▊ }}}$ 3.4%, 528 B
dist/elements/Translation ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▋ }}}$ 2.9%, 440 B
dist/utilities/traverseForLocalizedFields.js ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 399 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 339 B
dist/utilities/getVisibleEntities.js ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 329 B
dist/utilities/getNavGroups.js ${{\color{Goldenrod}{ ▌ }}}$ 2.0%, 301 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 180 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 159 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 152 B
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 146 B
(other) ${{\color{Goldenrod}{ ███████████████████▉ }}}$ 79.7%, 12.27 KB
Details

Next to the size is how much the size has increased or decreased compared with the base branch of this PR.

  • ‼️: Size increased by 20% or more. Special attention should be given to this.
  • ⚠️: Size increased in acceptable range (lower than 20%).
  • ✅: No change or even downsized.
  • 🗑️: The out file is deleted: not found in base branch.
  • 🆕: The out file is newly found: will be added to base branch.

@JessRynkar JessRynkar marked this pull request as ready for review December 17, 2025 12:36
@JessRynkar JessRynkar changed the base branch from feat/experimental-localize-metadata to feat/experimental-localize-metadata-ui December 18, 2025 14:59
@JessRynkar JessRynkar merged commit 73937b7 into feat/experimental-localize-metadata-ui Jan 14, 2026
98 checks passed
@JessRynkar JessRynkar deleted the feat/experimental-localize-metadata-migration branch January 14, 2026 10:16
JessRynkar added a commit that referenced this pull request Jan 14, 2026
Adds ui changes necessary for the localized status to display correctly
in the edit view and versions view.


##### Related PRs in this feature

- [feat: adds versions.drafts.localizeStatus and allows unpublish
per‑locale #14667](#14667)
- [feat(ui): experimental localize metadata UI
#14699](#14699)
- [chore: localize status migration work
#14862](#14862)

---------

Co-authored-by: Jessica Chowdhury <[email protected]>
Co-authored-by: Sasha <[email protected]>
Co-authored-by: Jessica Rynkar <[email protected]>
JessRynkar added a commit that referenced this pull request Jan 16, 2026
…r-locale functionality (#14667)

## Localized Status (Experimental) 

This PR introduces a new **experimental** option that allows each locale
to track and manage its own publication status independently, for
collection docs and globals.

### Configuration
To enable this feature, you need **two** configurations:

1. Enable the experimental flag in your `payload.config`:

```ts
experimental: {
  localizeStatus: true, // default: `false`
}
```

2. Enable it on specific collections/globals:
```ts
export const Posts: CollectionConfig = {
  slug: 'posts',
  versions: {
    drafts: {
      localizeStatus: true, // default: false
    },
  },
  // ...
}
```

## Key Changes

When enabled:

- **Per-locale status tracking** - Each locale maintains its own
published/draft status
- **Independent publishing** - Publish or unpublish individual locales
without affecting others
- **Locale-aware UI** - Admin panel shows status for the currently
active locale
- **Localized version history** - Versions list reflects the current
locale's status

## Improved Behavior
- Creating a document in one locale sets that locale to the specified
status and other locales default to draft
- You can publish/unpublish specific locales independently
- Collection list views show status for the currently active locale
- Document edit view displays the current locale's status

## Migration Required (If you already have version data)

> If this is a new project then you only need to enable the flags. If
you have existing data you will want to continue with the migration
guide below.

⚠️ Breaking Change: When `localizeStatus` is enabled, existing `_status`
fields will need to be migrated from strings to locale objects.

### ➡️ Step 1
Before doing anything, **take a backup of your current database**.

### ➡️ Step 2
Stop your dev server if it is running

### ➡️  Step 3
**Create migration file**
```ts
// run the following to create a blank
// migration file named `localize_status`
payload migrate:create localize_status
```

**Add migration code**

🔵 **PostgreSQL / SQLite**:
```ts
import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-postgres'
import { sql } from '@payloadcms/db-postgres'
import { localizeStatus } from 'payload/migrations'

export async function up({ db, payload }: MigrateUpArgs): Promise<void> {
  await localizeStatus.up({
    collectionSlug: 'posts', // 👈 Change to your collection
    db,
    payload,
    sql,
  })
}

export async function down({ db, payload }: MigrateDownArgs): Promise<void> {
  await localizeStatus.down({
    collectionSlug: 'posts', // 👈 Change to your collection  
    db,
    payload,
    sql,
  })
}
```

🟢  **MongoDB**:
```ts
import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-mongodb'
import { localizeStatus } from 'payload/migrations'

export async function up({ payload }: MigrateUpArgs): Promise<void> {
  await localizeStatus.up({
    collectionSlug: 'posts', // 👈 Change to your collection
    payload,
  })
}

export async function down({ payload }: MigrateDownArgs): Promise<void> {
  await localizeStatus.down({
    collectionSlug: 'posts', // 👈 Change to your collection
    payload,
  })
}
```

### ➡️ Step 4
Run the migration
```ts
payload migrate
```

### ➡️ Step 5
Set `localizeStatus: true` 

**Payload Config**
```ts
// payload config file
experimental: {
  localizeStatus: true, // <-- add this
}
```

**Collection Config**
```ts
// collection you want to migrate
export const Posts: CollectionConfig = {
  slug: 'posts',
  versions: {
    drafts: {
      localizeStatus: true, // <-- add this
    },
  },
  // ...
}
```

### ➡️ Step 6
Run `pnpm dev` and test out the feature.
  
## Related PRs in this feature

- [feat: adds versions.drafts.localizeStatus and allows unpublish
per‑locale #14667](#14667)
- [feat(ui): experimental localize metadata UI
#14699](#14699)
- [chore: localize status migration work
#14862](#14862)

---------

Co-authored-by: Jessica Chowdhury <[email protected]>
Co-authored-by: Sasha <[email protected]>
Co-authored-by: Jessica Rynkar <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants