Перейти к содержимому
Все материалы

Почему Payload CMS тормозит на сложных страницах: разработчики нашли способ ускорить открытие форм на 93%

14 октября 2026 г.•Александр Андреев

В Payload CMS обнаружили проблему производительности, из-за которой административная панель в проектах с большим количеством блоков открывалась десятки секунд. Причиной оказались повторные вычисления при обработке схемы полей. Разработчики подготовили исправление, которое в тестовой конфигурации сократило время первого открытия формы с 5,2 до 0,36 секунды.

13 октября 2026 года в репозитории Payload появились два pull request с оптимизацией: один для основной ветки разработки, второй для Payload 3.x. История показательна ещё и тем, как долго проблема оставалась неопознанной — сначала подозревали Next.js, Turbopack и особенности режима разработки, и лишь профилирование конкретного проекта показало, что значительная часть времени уходит внутрь самого Payload.

Когда админка начинает тормозить

Представим достаточно типичный проект на Payload CMS: корпоративный сайт с конструктором страниц.

Разработчики создают набор блоков, из которых редакторы собирают содержимое: текстовые секции, карточки товаров, галереи, формы, баннеры. В простом проекте таких блоков около десятка, в крупном — несколько десятков или больше сотни. Каждый блок содержит собственные поля, часть из них — вложенные группы, массивы и редакторы Rich Text, внутри которых тоже могут использоваться блоки.

По мере развития проекта конфигурация усложняется, и однажды административная панель начинает открываться заметно медленнее — причём даже тогда, когда в базе практически нет документов.

Первое подробное описание такой ситуации появилось в обсуждении #14230 в октябре 2025 года. Автор работал с проектом примерно из 25 типов блоков и 20 коллекций: в режиме разработки страницы открывались от 10 до 60 секунд, а потребление оперативной памяти доходило до 13 ГБ и продолжало расти. Собранное для продакшена приложение вёл себя значительно лучше.

Похожие симптомы описывали и другие участники: кому-то помогала смена версии Next.js, кому-то нет, и универсального решения в обсуждении не находилось. Самой очевидной версией по-прежнему оставались Next.js и Turbopack.

Причину нашли внутри Payload

В июле 2026 года к обсуждению присоединился разработчик под псевдонимом gtomaka. Он столкнулся с той же проблемой, но вместо экспериментов с версиями Next.js профилировал серверную часть приложения.

Результат оказался неожиданным: практически всё время обработки запроса уходило на одну функцию Payload — buildClientFieldSchemaMap. Она строит карту путей полей коллекции, которой пользуется административная панель.

В его проекте карта содержала 196 295 путей и строилась около 82 секунд. Для сравнения: коллекция с тремя полями обрабатывается примерно за одну миллисекунду. Типов блоков в конфигурации было 97.

Результат вычисления кешировался, но кеш сбрасывался при каждой реинициализации Payload — в режиме разработки это происходило при каждой перезагрузке кода, так что ждать построения карты приходилось заново.

Важная деталь: время выполнения росло непропорционально количеству блоков. Это указывало не на нехватку ресурсов, а на проблему алгоритма.

Что именно замедляло обработку

Чтобы понять причину, нужно немного разобраться в устройстве карты полей.

Payload поддерживает сложные вложенные структуры: коллекция страниц может содержать поле layout с блоками, у каждого блока свои поля, а некоторые из них включают дополнительные вложенности. Для такой конфигурации строится множество путей, описывающих расположение каждого поля:

layout
layout.hero
layout.hero.title
layout.hero.description
layout.hero.buttons
layout.hero.buttons.label
layout.hero.buttons.url
layout.content
layout.content.body

Это упрощённая иллюстрация: реальные внутренние пути Payload устроены сложнее.

Проблема возникала при обработке полей Rich Text. Для каждого такого поля функция заново проходила по всей карте, отбирая записи с подходящим префиксом. В обсуждении был приведён характерный фрагмент:

for (const [path, subField] of schemaMap.entries()) {
  if (path.startsWith(`${schemaPath}.`)) {
    richTextFieldSchemaMap.set(path, subField)
  }
}

Сам по себе код безобиден. Но общая стоимость вычислений равна произведению количества Rich Text-полей на размер карты — и оба множителя растут вместе с конфигурацией. При двухстах тысячах записей и тысяче Rich Text-полей счёт проверок идёт на сотни миллионов.

Отсюда и характерное поведение: после очередного расширения библиотеки блоков время ожидания увеличивалось уже не на миллисекунды, а на секунды.

Первое исправление: с 82 секунд до 250 миллисекунд

Найдя причину, gtomaka подготовил экспериментальную оптимизацию. Ключи карты с общим префиксом после сортировки оказываются рядом, поэтому вместо полного просмотра карты для каждого Rich Text-поля достаточно двоичного поиска по отсортированным ключам.

На его конфигурации время обработки сократилось с 82 секунд до 0,25 секунды — примерно в 328 раз. Разработчик сравнил результаты до и после изменения алгоритма: все 196 295 записей карты совпали.

В августе он опубликовал отдельный репозиторий payload-block-perf с воспроизводимым тестом: количество блоков можно менять и сравнивать стандартную реализацию с оптимизированной. Замеры исходной реализации хорошо показывают характер проблемы:

Блоков в конфигурации   Время обработки
10                      0,5 секунды
40                      8 секунд
70                      128 секунд

Это синтетические измерения, а не универсальный прогноз для любого проекта, но они демонстрируют нелинейный рост: удвоение конфигурации увеличивает время примерно вчетверо.

В том же репозитории описана вторая похожая «горячая точка» — повторное вычисление разрешений для подключаемых блоков, которая к тому же не кешируется и выполняется на каждый запрос админки. Свои исправления автор публикует с явной пометкой, что это неофициальный проект, не связанный с Payload CMS, — а патч, затрагивающий разграничение доступа, без собственной проверки применять нельзя.

Новая оптимизация: ускорение открытия формы на 93%

13 октября 2026 года работа получила продолжение: в репозитории Payload появились два pull request — #18698 для основной ветки и #18697 для Payload 3.x.

Новая реализация использует другой подход: записи карты предварительно группируются по Rich Text-предкам за один проход, а результаты кешируются через WeakMap. Полный повторный обход для каждого Rich Text-поля больше не нужен: вложенная запись попадает в группу каждого своего Rich Text-предка, что даёт тот же результат, что и прежний префиксный скан. Кеш по WeakMap безопасен при перезагрузке конфигурации: новая конфигурация создаёт новую карту, поэтому старые группы вернуться не могут. По словам автора, результат идентичен прежнему — те же ключи, значения и порядок ключей.

В описании изменений приведены измерения на конфигурации с 1 260 Rich Text-полями: первое открытие формы сократилось с 5,2 до 0,36 секунды — ускорение примерно на 93%. Само построение карты полей в этом сценарии выполняется примерно в 28 раз быстрее.

Важно правильно интерпретировать эти цифры. Ускорение на 93% относится к конкретному тестовому сценарию с большим количеством Rich Text-полей, а не ко всей административной панели Payload CMS. На проектах с небольшой библиотекой блоков разница может оказаться практически незаметной. Но там, где построение карты полей становится основным узким местом, эффект потенциально значительный.

На момент подготовки материала оба pull request открыты и ещё не объединены — считать исправление частью опубликованного стабильного релиза рано.

Почему это особенно важно для конструкторов страниц

Payload CMS часто выбирают именно из-за гибкости моделирования контента: разработчик создаёт библиотеку блоков, а редакторы самостоятельно собирают из них страницы.

На сайте застройщика это могут быть блоки планировок, преимуществ жилого комплекса, инфраструктуры, галерей, документов и форм обратной связи. На корпоративном портале — сотрудники, подразделения, новости, документы и интерактивные элементы.

Сами по себе эти структуры не обязательно содержат много данных — сложной может быть именно конфигурация, особенно если блоки переиспользуются в разных коллекциях и содержат вложенные поля и редакторы Lexical.

Отсюда главная особенность этой проблемы: обычная оптимизация запросов к базе данных здесь почти бесполезна, потому что задержка возникает ещё на этапе обработки конфигурации. Можно установить более быстрые диски, увеличить объём оперативной памяти или перенести PostgreSQL на отдельный сервер — лишние обходы карты полей это не уберёт. Необходимо менять алгоритм.

Что можно сделать уже сейчас

Использовать глобальные определения блоков

Документация Payload рекомендует определять переиспользуемые блоки один раз в общей конфигурации, а в полях ссылаться на них по slug:

import { buildConfig } from 'payload'
import type { Block } from 'payload'

const TextBlock: Block = {
  slug: 'textBlock',
  fields: [
    {
      name: 'text',
      type: 'text',
    },
  ],
}

export default buildConfig({
  blocks: [TextBlock],
  collections: [
    {
      slug: 'pages',
      fields: [
        {
          name: 'layout',
          type: 'blocks',
          blocks: ['textBlock'],
        },
      ],
    },
  ],
})

Так полная конфигурация блока не дублируется в каждом месте использования — тот же механизм работает и для блоков внутри Lexical-редактора. Документация отдельно отмечает, что ссылки на глобальные блоки помогают оптимизировать производительность.

У подхода есть ограничения: конфигурация блока становится общей для всех мест использования, а сам блок изолируется от конфигурации коллекции, в которую подключён, — например, правила доступа внутри него не получают контекст конкретного документа. Поэтому заменять все локальные блоки глобальными без анализа существующей логики не стоит.

Проверить, где именно возникает задержка

Если административная панель медленно открывается в режиме разработки, не стоит сразу обвинять Next.js или базу данных. Полезно разделить время компиляции, выполнения запроса на сервере и отрисовки интерфейса: если компиляция занимает доли секунды, а ответ сервера формируется десятки секунд, стоит профилировать серверный код — в частности, проверить время выполнения buildClientFieldSchemaMap.

При этом не следует считать эту функцию причиной любых медленных сценариев. В том же обсуждении один из участников обнаружил у себя совсем другую проблему — цепочку промисов внутри собственного хука; после её исправления страница в dev-режиме стала открываться примерно за секунду вместо тридцати. Хороший пример того, почему профилирование полезнее предположений.

Не применять экспериментальные патчи без проверки

В payload-block-perf доступны экспериментальные исправления, но это не официальный выпуск Payload, а патчи стороннего разработчика под конкретные версии. Для рабочего проекта разумнее дождаться принятия исправления в основной репозиторий и его появления в стабильной версии.

Что в итоге

Payload CMS позволяет создавать сложные модели контента, но такая гибкость предъявляет требования к эффективности обработки конфигурации. История с buildClientFieldSchemaMap показала, как относительно небольшой участок кода с неудачной вычислительной сложностью становится серьёзным ограничением производительности: в отдельных проектах построение карты полей занимало десятки секунд, экспериментальная оптимизация сократила его с 82 до 0,25 секунды, а новое предложение ускорило первое открытие формы с 5,2 до 0,36 секунды.

При этом для большинства небольших проектов проблема может вообще не проявляться. Главное практическое следствие касается крупных конфигураций: если Payload начинает тормозить по мере усложнения библиотеки блоков, стоит проверить обработку схемы полей, прежде чем менять сервер, базу данных или версию Next.js.

Теперь остаётся дождаться принятия исправления и его включения в стабильный релиз Payload 3.x. Для разработчиков крупных сайтов и приложений с большим количеством блоков это обновление может оказаться заметнее многих новых возможностей административной панели.

Правило: если админка замедляется вместе с ростом конфигурации, а не объёма данных, — сначала профилирование, потом железо.

Источники

https://github.com/payloadcms/payload/discussions/14230https://github.com/gtomaka/payload-block-perfhttps://github.com/payloadcms/payload/pull/18698https://github.com/payloadcms/payload/pull/18697https://payloadcms.com/docs/fields/blocks
Назад в блог
Почему Payload CMS тормозит на сложных страницах: разработчики нашли способ ускорить открытие форм на 93% | Payload по-русски