Upgrade Information
The following steps are necessary during updating to newer versions.
Upgrade to 2026.4.0
Embeddings
- New
embeddings.models.<id>.field_filter: per model and data object class an allow or a block list of grid column keys, optionally narrowed to one language as{key, locale}. Absent, every field is embedded as before. See Filters tab. embeddings.excluded_fieldsis deprecated in favour offield_filter, emits a deprecation at container build, and will be removed in 2027.1.0. Until then it keeps working, and still removes a key an allow list names.- An element a filter leaves with nothing to embed loses that model's stored vector and text siblings on the next re-embed, instead of keeping the ones it had. It counts as processed from then on, so a full re-embed completes with such elements in scope. An element out of scope keeps its vectors as before.
- A
mode: allowentry naming an image, geo or URL-slug key exactly embeds it;passwordandencryptedFieldnever are. Without afield_filternothing changes. - Studio API: the configuration carries
allowListFiltersandblockListFilters; each entry'sfieldscomes back as stored plus a read-onlyinactiveflag. bpt:embeddings:search-eval --dump-textcomposes with the model bound tosemantic_text_search, and fails when that usage has no model.auth_tokenandoptions.headersof an embedding model now reject unescaped%name%parameter references in addition to%env(...)%placeholders, in Studio, inconfig/packages/*.yamland in theembeddingswrite-target yaml. A configuration that uses one fails validation after the update; replace it with the literal value, or escape a literal%as%%.- On Studio saves and uploads, the text of document and plain-text assets is extracted by the index queue worker instead of during the request, so their vectors appear once the worker has processed the asset.
- Inputs the provider rejects permanently (HTTP 400/413/422) are isolated and stamped with an
emb_<model>[__<format>]_failedtimestamp; thebpt_embedding_reconcilemaintenance task retries them at most once every 24 hours. No index recreation is needed.
Duplicates Detection
- A running analysis can only be canceled by the user who started it or by an admin
Semantic Search (experimental)
- Semantic grid search now cuts off weak matches with a default minimum score (text 20 %, image 8 %) instead
of returning the top 150 hits. Set
semantic_search.targets.<text|image>.default_min_scoreto0(or sendminScore: 0) to keep every hit. - Candidates per search are limited by
semantic_search.candidate_cap(default 10000) instead of 150, so totals and paging go deeper; lower the cap on large indexes if searches get slow. - The global semantic search endpoint applies the same default minimum score; its candidates per index are
configurable via
semantic_search.global_search_candidate_cap(default 150, unchanged). - CSV/XLSX exports and batch actions of a semantic grid now apply the semantic filter with the job owner's permissions, so they contain the same elements as the grid.
- When the inference service cannot embed the query, grid smart search, its exports and its batch actions now
fail with a user-facing error (
bpt_semantic_search_unavailable) instead of returning non-semantic results; export and batch jobs end as failed. The global semantic search endpoint returns the same message. - New
semantic_searchconfiguration record (System → Semantic Search Configuration); run the migrations to seed it. - Requires
pimcore/studio-backend-bundle,pimcore/studio-ui-bundleandpimcore/generic-data-index-bundle2026.4.
Upgrade to 2026.3.5
- [Security] Alternative Element Trees: the Symfony expression of a relation tree level
(
relationSymfonyExpression) is now evaluated with read-only values of the related object (GHSA-x6vx-2g29-6ff4). Symfony's ExpressionLanguage is not a sandbox: anyone allowed to edit tree configurations could call every public method of the related object, e.g. reach the database connection throughobject.getDao(), or save or delete elements. Field getters (also of related objects, object bricks, field collections and localized fields, e.g.object.getName("de")), element getters (getId(),getKey(),getFullPath(),getParent(), dates, ...), the getters of field values and operators like~keep working, e.g.object.getName() ~ " " ~ object.getManufacturer().getName(). Any other method, e.g.getDao(),save(),delete(), setters,getClass()orgetChildren(), is rejected: saving such a tree configuration fails validation, and a stored one fails when the tree is built. Theconstant()function stays unavailable. See the Pimcore core upgrade notes on expressions for the full list. pimcore/pimcore^2026.3.5is now required, as it provides the read-only expression language.
Upgrade to 2026.3.4
- Alternative Element Trees: the hash that detects whether an object's tree rows must be rebuilt now keeps empty
levels and the borders between levels. Stored hashes change, so each object is re-checked the next time it is
saved and its rows are rebuilt once. To repair trees that already hold stale rows, run
bin/console bpt:aet:rebuild-tree -a.
Upgrade to 2026.3.3
- Duplicate detection: a sweep page whose search request times out (
cluster_courtesy.request_timeout_ms) or comes back with a failed shard now aborts that sweep step, so the run ends finished with errors instead of silently finished with incomplete results. The failed page is not checkpointed, so the run never records progress past what it missed. The run keeps a single resume cursor, though: once the fuzzy tier has checkpointed, a retry of a failed exact sweep starts from the beginning rather than at the last exact page. If runs now end with errors, raiserequest_timeout_msor check the search cluster's health. - Duplicate detection: a run that stopped at an execution budget before covering every element now shows a warning on the duplicates configuration screen.
Upgrade to 2026.3.2
- Duplicate detection: the path restriction of a scope or class is now a list of include/exclude folder
rules (
paths) and applies to group members as well as references, in both the exact and the fuzzy tier. Previously the fuzzy tier could group elements from outside the configured path. The next analysis withdraws such members; no full run is needed. path_prefixis deprecated; it is read as one include rule. Replace it withpaths, see Folder rules.- A path now covers whole folders only:
/Productsno longer matches/Products-Old. - Studio API: the duplicates configuration schemas carry
paths(list of{path, mode}); the formerpathPrefixis deprecated and, whenpathsis empty, still read as one include rule.
Upgrade to 2026.3.0
- Added Embeddings (experimental) – off by default.
- New public API -
EmbeddingProviderInterface,AbstractHttpEmbeddingProvider,EmbeddingModelConfigandEmbeddingConfigExceptionare public so a custom provider can be implemented.
Embeddings are adding a new table, please execute the migration command after updating the bundle:
bin/console doctrine:migrations:migrate --prefix='Pimcore\Bundle\BackendPowerToolsBundle\Migrations'
Upgrade to 2026.2.6
Frontend Build Ships as a Packaged Archive
The compiled Studio frontend is no longer committed as an expanded
public/studio/build/ directory. It now ships as a single archive
(build-dist/build-<id>.zip) that is extracted into public/studio/build/
automatically during cache warmup.
pimcore/studio-ui-bundle ^2026.2.1 is now required, as it provides the
archive extraction.
Note: Read-only filesystem deployments must run
bin/console cache:warmup(orcache:clear) during the build/deploy phase while the bundle directory (usually undervendor/) is still writable. Standard Pimcore deployments already do this. Whenassets:installruns in copy mode, runcache:warmupbefore it, otherwise no frontend assets are copied. If the filesystem becomes read-only before the first warmup, the bundle fails withBuildArchiveNotWritableExceptionbecause there is no build to serve.
Upgrade to 2026.1.0
- The bundle installer now implements
PostInstallCommandsProviderInterfacefrom Pimcore's InstallBundle. This means the post-install commandbpt:aet:rebuild-tree -ais automatically executed duringpimcore:installwhen using Install Profiles. Manual execution of this command afterpimcore:bundle:installis still required as before. - The messenger transport DSN is now configurable via the
%pimcore.messenger.transport_dsn_prefix%container parameter instead of being hardcoded todoctrine://default. This allows the installer to wire the transport DSN from environment variables (e.g.PIMCORE_MESSENGER_TRANSPORT_DSN_PREFIX). - Added support to
PHP8.5. - Removed support to
PHP8.3and Symfonyv6.