Skip to content

Conversation

jacobsfletch
Copy link
Member

@jacobsfletch jacobsfletch commented Oct 1, 2025

Fixes #13938. Requires #14012.

Exports a new slugField. This is a wrapper around the text field, that you can drop into any field schema.

A slug is a unique, URL-friendly string that identifies a particular document, often used to construct the URL of a webpage. Slugs are a fundamental concept for seemingly every project.

Traditionally, you'd build this field from scratch, but there are many edge cases and nice-to-haves to makes this difficult to maintain by hand. For example, it needs to automatically generate based on the value of another field, provide UI to lock and re-generate the slug on-demand, etc.

Background:

When autosave is enabled, the slug is only ever generated once after the initial create, leading to single character, or incomplete slugs.

For example, it is expected that "My Title" → "my-title, however ends up as "m".

This PR overhauls the field to feel a lot more natural. Now, we only generate the slug through:

  1. The create operation, unless the user has modified the slug manually
  2. The update operation, if:
    a. Autosave is not enabled and there is no slug
    b. Autosave is enabled, the doc is unpublished, and the user has not modified the slug manually

The slug should stabilize after all above criteria have been met, because the URL is typically derived from the slug. This is to protect modifying potentially live URLs, breaking links, etc. without explicit intent.

This fix, along with all the other features, is now standardized behind the new slugField:

import type { CollectionConfig } from 'payload'
import { slugField } from 'payload'

export const MyCollection: CollectionConfig = {
  // ...
  fields: [
   // ...
   slugField()
  ]
}

In the future we could also make this field smart enough to auto increment itself when its generated slug is not unique.


Copy link
Contributor

github-actions bot commented Oct 1, 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 753.90 KB ✅ No change
packages/payload/meta_index.json esbuild/index.js 1.22 MB ⚠️ +1.55 KB (+0.1%)
packages/payload/meta_shared.json esbuild/exports/shared.js 162.17 KB ⚠️ +82 B (+0.1%)
packages/richtext-lexical/meta_client.json esbuild/exports/client_optimized/index.js 263.64 KB ✅ No change
packages/ui/meta_client.json esbuild/exports/client_optimized/index.js 1.14 MB ⚠️ +1.32 KB (+0.1%)
packages/ui/meta_shared.json esbuild/exports/shared_optimized/index.js 14.39 KB ✅ No change
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}{ ████████████████████ }}}$ 80.3%, 601.78 KB
dist/views/Version ${{\color{Goldenrod}{ █▋ }}}$ 6.6%, 49.59 KB
dist/views/Document ${{\color{Goldenrod}{ ▌ }}}$ 2.0%, 15.25 KB
dist/views/List ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 10.29 KB
dist/views/Root ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 8.24 KB
dist/views/API ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 5.98 KB
dist/views/Versions ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 5.96 KB
dist/views/Account ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 5.32 KB
dist/elements/DocumentHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 4.81 KB
dist/elements/Nav ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 4.67 KB
dist/views/Login ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 4.39 KB
dist/views/Dashboard ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 3.68 KB
dist/layouts/Root ${{\color{Goldenrod}{ }}}$ 0.4%, 3.11 KB
dist/views/ForgotPassword ${{\color{Goldenrod}{ }}}$ 0.4%, 3.09 KB
dist/templates/Default ${{\color{Goldenrod}{ }}}$ 0.4%, 2.83 KB
dist/views/CreateFirstUser ${{\color{Goldenrod}{ }}}$ 0.4%, 2.76 KB
dist/views/BrowseByFolder ${{\color{Goldenrod}{ }}}$ 0.3%, 2.60 KB
dist/views/CollectionFolders ${{\color{Goldenrod}{ }}}$ 0.3%, 2.46 KB
dist/views/ResetPassword ${{\color{Goldenrod}{ }}}$ 0.3%, 2.41 KB
dist/views/Logout ${{\color{Goldenrod}{ }}}$ 0.3%, 1.91 KB
(other) ${{\color{Goldenrod}{ ████▉ }}}$ 19.7%, 147.44 KB

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

Path Size
../../node_modules ${{\color{Goldenrod}{ █████████████████▎ }}}$ 69.2%, 841.06 KB
dist/fields/hooks ${{\color{Goldenrod}{ ▊ }}}$ 3.4%, 41.84 KB
dist/collections/operations ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 36.91 KB
dist/auth/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.30 KB
dist/queues/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.04 KB
dist/globals/operations ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 11.90 KB
dist/fields/config ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 11.57 KB
dist/utilities/configToJSONSchema.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 11.54 KB
dist/fields/validations.js ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.06 KB
dist/bin/generateImportMap ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.27 KB
dist/collections/config ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.88 KB
dist/database/migrations ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.79 KB
dist/uploads/fetchAPI-multipart ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.74 KB
dist/index.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.46 KB
dist/collections/endpoints ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.40 KB
dist/config/orderable ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.27 KB
dist/auth/strategies ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 5.50 KB
dist/config/sanitize.js ${{\color{Goldenrod}{ }}}$ 0.4%, 5.44 KB
dist/auth/endpoints ${{\color{Goldenrod}{ }}}$ 0.4%, 5.41 KB
dist/utilities/telemetry ${{\color{Goldenrod}{ }}}$ 0.4%, 5.31 KB
(other) ${{\color{Goldenrod}{ ███████▋ }}}$ 30.8%, 373.64 KB

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

Path Size
../../node_modules ${{\color{Goldenrod}{ ███████████████████▉ }}}$ 79.9%, 126.93 KB
dist/fields/validations.js ${{\color{Goldenrod}{ █▌ }}}$ 6.3%, 10.06 KB
dist/fields/baseFields ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 2.79 KB
dist/utilities/deepCopyObject.js ${{\color{Goldenrod}{ ▍ }}}$ 1.6%, 2.48 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/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/collections/config ${{\color{Goldenrod}{ }}}$ 0.4%, 570 B
dist/bin/generateImportMap ${{\color{Goldenrod}{ }}}$ 0.4%, 559 B
dist/auth/sessions.js ${{\color{Goldenrod}{ }}}$ 0.3%, 545 B
dist/utilities/getSafeRedirect.js ${{\color{Goldenrod}{ }}}$ 0.3%, 423 B
dist/utilities/deepMerge.js ${{\color{Goldenrod}{ }}}$ 0.3%, 413 B
dist/utilities/getFieldPermissions.js ${{\color{Goldenrod}{ }}}$ 0.2%, 391 B
dist/utilities/formatLabels.js ${{\color{Goldenrod}{ }}}$ 0.2%, 380 B
dist/utilities/appendUploadSelectFields.js ${{\color{Goldenrod}{ }}}$ 0.2%, 360 B
dist/utilities/transformColumnPreferences.js ${{\color{Goldenrod}{ }}}$ 0.2%, 348 B
(other) ${{\color{Goldenrod}{ █████ }}}$ 20.1%, 31.96 KB

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

Path Size
dist/lexical/plugins ${{\color{Goldenrod}{ ██▉ }}}$ 11.6%, 30.20 KB
dist/features/experimental_table ${{\color{Goldenrod}{ ██▎ }}}$ 9.1%, 23.66 KB
dist/lexical/ui ${{\color{Goldenrod}{ ██▎ }}}$ 9.0%, 23.36 KB
dist/features/blocks ${{\color{Goldenrod}{ ██▏ }}}$ 8.6%, 22.41 KB
dist/packages/@lexical ${{\color{Goldenrod}{ █▊ }}}$ 7.3%, 18.99 KB
dist/features/link ${{\color{Goldenrod}{ █▋ }}}$ 6.9%, 17.96 KB
dist/features/toolbars ${{\color{Goldenrod}{ █▋ }}}$ 6.8%, 17.59 KB
dist/features/upload ${{\color{Goldenrod}{ █▎ }}}$ 5.2%, 13.48 KB
dist/features/textState ${{\color{Goldenrod}{ █ }}}$ 4.2%, 11.02 KB
dist/features/relationship ${{\color{Goldenrod}{ ▉ }}}$ 3.5%, 9.09 KB
dist/lexical/utils ${{\color{Goldenrod}{ ▊ }}}$ 3.1%, 8.08 KB
dist/features/debug ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 7.39 KB
dist/features/converters ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.04 KB
dist/utilities/fieldsDrawer ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.01 KB
dist/lexical/config ${{\color{Goldenrod}{ ▌ }}}$ 2.0%, 5.10 KB
dist/features/lists ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 4.95 KB
dist/lexical/theme ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 4.01 KB
dist/features/format ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 3.46 KB
dist/lexical/LexicalEditor.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 3.17 KB
dist/features/indent ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 2.50 KB
(other) ${{\color{Goldenrod}{ ██████████████████████ }}}$ 88.4%, 230.38 KB

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

Path Size
../../node_modules ${{\color{Goldenrod}{ ████████████▋ }}}$ 50.5%, 572.88 KB
dist/elements/FolderView ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 29.14 KB
dist/elements/BulkUpload ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 26.94 KB
dist/elements/WhereBuilder ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 16.16 KB
dist/views/Edit ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.86 KB
dist/fields/Relationship ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 15.40 KB
dist/elements/Table ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.29 KB
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 14.96 KB
dist/fields/Blocks ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 12.68 KB
dist/fields/Upload ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 11.49 KB
dist/elements/PublishButton ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 8.73 KB
dist/providers/Folders ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.49 KB
dist/elements/LivePreview ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB
dist/elements/QueryPresets ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.36 KB
dist/elements/ListHeader ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.83 KB
dist/elements/HTMLDiff ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.81 KB
dist/fields/Array ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.55 KB
dist/views/CollectionFolder ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.37 KB
dist/views/List ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.96 KB
dist/elements/ReactSelect ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.91 KB
(other) ${{\color{Goldenrod}{ ████████████▍ }}}$ 49.5%, 561.45 KB

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

Path Size
dist/graphics/Logo ${{\color{Goldenrod}{ █████▋ }}}$ 22.6%, 3.12 KB
../../node_modules ${{\color{Goldenrod}{ ████▊ }}}$ 19.2%, 2.65 KB
dist/graphics/Icon ${{\color{Goldenrod}{ ██▊ }}}$ 11.0%, 1.52 KB
dist/utilities/formatDocTitle ${{\color{Goldenrod}{ ██▍ }}}$ 9.6%, 1.32 KB
dist/providers/TableColumns ${{\color{Goldenrod}{ █▌ }}}$ 6.2%, 862 B
dist/utilities/groupNavItems.js ${{\color{Goldenrod}{ █▍ }}}$ 5.9%, 814 B
dist/utilities/api.js ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 756 B
dist/elements/Translation ${{\color{Goldenrod}{ ▉ }}}$ 3.6%, 493 B
dist/utilities/handleTakeOver.js ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 440 B
dist/elements/withMergedProps ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 339 B
dist/elements/WithServerSideProps ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 232 B
dist/utilities/handleGoBack.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 168 B
dist/fields/mergeFieldStyles.js ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 159 B
dist/forms/Form ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 147 B
dist/utilities/abortAndIgnore.js ${{\color{Goldenrod}{ ▎ }}}$ 1.1%, 146 B
dist/utilities/hasSavePermission.js ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 136 B
dist/utilities/handleBackToDashboard.js ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 129 B
dist/utilities/findLocaleFromCode.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 84 B
dist/utilities/sanitizeID.js ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 77 B
dist/utilities/isEditing.js ${{\color{Goldenrod}{ }}}$ 0.4%, 59 B
(other) ${{\color{Goldenrod}{ ███████████████████▎ }}}$ 77.4%, 10.68 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.

@jacobsfletch jacobsfletch changed the title fix(templates): auto gen slug through autosave fix(templates): auto generate slug through initial autosave Oct 1, 2025
@jacobsfletch jacobsfletch enabled auto-merge (squash) October 2, 2025 21:20
paulpopus
paulpopus previously approved these changes Oct 2, 2025
@jacobsfletch jacobsfletch disabled auto-merge October 2, 2025 23:42
@jacobsfletch jacobsfletch changed the title fix(templates): auto generate slug through initial autosave feat: slug field Oct 4, 2025
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.

Slug will be generated pre-maturely on first draft save resulting in single letter slugs
2 participants