Pimcore Studio Setup Guide: Backend & Infrastructure for Developers
Pimcore Studio is the newest addition to the Pimcore platform, that replaces current ExtJS-based admin interface. It is built with React, and it provides a more modern and improved user experience.
In order to access Studio UI features, multiple services need to be installed and configured beforehand. This guide will walk you through the required installation steps and give you an overview of the required services.
Note: We used DDEV for the local setup. The starting point for this guide is an existing DDEV-based Pimcore/Symfony project, which already provides the base local services. From there, we add and configure the extra services required for Studio UI. If you are new to DDEV, see the official documentation.
Architecture Overview
Before jumping into the set-up process, we need to understand how Pimcore Studio fits into the overall system.
At a high level, Pimcore Studio requires the following:
- Studio UI - administration interface for Pimcore built in React.
- Studio Backend - central hub for API endpoints (provides docs via swagger-ui).
- Several supporting services:
- OpenSearch - indexing and search
- Symfony Messenger - background processing
- Mercure - real-time updates
Local Setup (DDEV)
This section covers everything required to get Studio UI running locally using DDEV.
OpenSearch
Studio UI relies on indexed data. Without OpenSearch, object trees and search functionality won’t work. To set up OpenSearch using DDEV, do the following:
1 - Install addon
ddev get ddev/ddev-opensearch
ddev restart
2 - Environment configuration
OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200
3 - Bundle configuration
pimcore_generic_data_index:
search_client:
hosts:
- '%env(OPENSEARCH_HOST)%:%env(OPENSEARCH_PORT)%'
Symfony Messenger
Studio UI depends on data in OpenSearch. To avoid manually running the command for index generation after each change on Pimcore elements, you can do the following:
1 - Add to .ddev/config.pimcore.yaml
web_extra_daemons:
- name: consumer
command: >-
while true; do
/var/www/html/bin/console messenger:consume
pimcore_core
pimcore_maintenance
pimcore_scheduled_tasks
pimcore_image_optimize
pimcore_asset_update
pimcore_generic_data_index_queue
pimcore_generic_execution_engine
--memory-limit=250M
--time-limit=3600;
done
directory: /var/www/html
2 - Restart DDEV
ddev restart
Mercure
Mercure enables real-time updates like job progress and notifications. To set up Mercure using DDEV, do the following:
1 - Install addon
ddev get Rindula/ddev-mercure
ddev restart
2 - Environment configuration
MERCURE_URL=https://<your-project>.ddev.site/hub
MERCURE_INTERNAL_URL=http://mercure:3000/.well-known/mercure
MERCURE_PUBLISHER_JWT_KEY=!ChangeThisMercureHubJWTSecretKey!
3 - Bundle configuration
pimcore_studio_backend:
mercure_settings:
jwt_key: "%env(MERCURE_PUBLISHER_JWT_KEY)%"
hub_url_client: '%env(MERCURE_URL)%'
hub_url_server: '%env(MERCURE_INTERNAL_URL)%'
Cross-origin issues with Mercure
By default, DDEV exposes Mercure on its own subdomain, such as mercure.your-project.ddev.site. If the Studio UI connects to that URL directly from your-project.ddev.site, the browser treats it as a different origin. In local setups, that leads to CORS-related issues.
The solution is to proxy the Mercure hub through the main site's nginx, so the browser only communicates with the same origin as the Pimcore application. Add the following location block inside the server block in .ddev/nginx_full/nginx-site.conf. If that file still contains the #ddev-generated marker at the top, remove it first so DDEV does not overwrite your changes:
location /hub {
proxy_pass http://mercure:3000/.well-known/mercure;
proxy_read_timeout 24h;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
}
With this in place, requests to https://your-project.ddev.site/hub are proxied internally to the Mercure container. MERCURE_INTERNAL_URL should still point directly to the Mercure container, for example http://mercure:3000/.well-known/mercure, because Pimcore publishes updates server-side over Docker’s internal network and does not need to go through the public nginx route.
Note: This nginx proxy is only necessary because Mercure runs on a different subdomain than the main application. In setups where Mercure already shares the same origin as the app (or is configured as an external service with its own public URL and proper CORS headers), this step can be skipped. You can read more about Mercure setup options in the [Pimcore documentation].
Upgrading to Pimcore 2025.4
Upgrading to version 2025.4 is a prerequisite for installing Pimcore Studio. If you are already on Pimcore version 12, you can follow the following steps:
1 - Update platform version
composer require pimcore/platform-version:2025.4
2 - Update dependencies
composer update pimcore/* symfony/*
3 - Run migrations
bin/console doctrine:migrations:migrate
Check deprecated bundles
Note that the following bundles will become deprecated and Pimcore currently doesn’t offer replacements for them:
- pimcore/file-explorer-bundle
- pimcore/system-info-bundle
- pimcore/seo-bundle
Bundle installation
Once the infrastructure is ready, you can start setting up the bundles. There are four bundles that you need to install:
Generic Data Index
Generic Data Index bundle indexes Pimcore elements (assets, objects, documents) into OpenSearch. To install it, follow the steps below:
1 - Install the required dependencies:
composer require pimcore/generic-data-index-bundle
2 - Make sure the bundle is enabled in the config/bundles.php file. The following line should be added:
Pimcore\Bundle\GenericDataIndexBundle\PimcoreGenericDataIndexBundle::class => ['all' => true],
3 - Install the bundle:
bin/console pimcore:bundle:install PimcoreGenericDataIndexBundle
Generic Execution Engine
Generic Execution Engine bundle enables progress tracking of long-running background jobs. To install it, follow the steps below:
1- Install the required dependencies:
composer require phpdocumentor/reflection-docblock symfony/property-info
2 - Make sure the bundle is enabled in the config/bundles.php file. The following line should be added:
Pimcore\Bundle\GenericExecutionEngineBundle\PimcoreGenericExecutionEngineBundle::class => ['all' => true],
3 - Install the bundle:
bin/console pimcore:bundle:install PimcoreGenericExecutionEngineBundle
Pimcore Studio Backend
Pimcore Studio Backend bundle serves as the central hub for API endpoints and RPC calls. To install it, follow the steps below:
1 - Install the required dependencies:
composer require pimcore/studio-backend-bundle
2 - Make sure the bundle is enabled in the config/bundles.php file. The following line should be added:
Pimcore\Bundle\GenericExecutionEngineBundle\PimcoreGenericExecutionEngineBundle::class => ['all' => true],
3 - Install the bundle:
bin/console pimcore:bundle:install PimcoreGenericExecutionEngineBundle
4 - Add the firewall configuration:
security:
firewalls:
pimcore_studio: '%pimcore_studio_backend.firewall_settings%'
access_control:
- { path: ^/pimcore-studio/api/(docs|docs/json|translations|user/reset-password)$, roles: PUBLIC_ACCESS }
- { path: ^/pimcore-studio/api, roles: ROLE_PIMCORE_USER }
Pimcore Studio UI
PimcoreStudioUiBundle provides React-based admin interface. To install it, follow the steps below:
1 - Install the required dependencies:
composer require pimcore/studio-ui-bundle
2 - Make sure the bundle is enabled in the config/bundles.php file. The following line should be added:
Pimcore\Bundle\StudioUiBundle\PimcoreStudioUiBundle::class => ['all' => true],
3 - Install the bundle:
bin/console pimcore:bundle:install PimcoreStudioUiBundle
Index creation
After successfully installing all four bundles, the next step is to understand how index creation and updates work. The main command used for managing indexes is:
bin/console generic-data-index:update:index
It provides several options for building and updating indexes:
Option | Shortcut | Description |
--class-definition-id=ID | -c | Update mapping and data for a specific data object class definition. |
--update-asset-index | -a | Update mapping and data for the asset index. |
--recreate_index | -r | Delete and recreate search indices. |
--update-global-aliases-only | (none) | Update only global index aliases for data-object and element-search indices. |
After the command finishes with index creation, you should be able to see your Pimcore elements in the React-based UI at its default URL {your-domain}/pimcore-studio.
Common Use Cases
If you create a new class definition or add a new attribute, you can update only that class:
bin/console generic-data-index:update:index -c Product
If you modify or remove an attribute, you should recreate the index for that class:
bin/console generic-data-index:update:index -c Product -r
Using the -c and -r options together allows you to rebuild only the affected index instead of all indexes, which helps reduce downtime and speeds up the update process.
After setting up Studio UI, you can start extending it using SDK hooks. Read more about customizing Pimcore Studio UI.
Conclusion
Pimcore Studio introduces a different way of working with the platform, but getting there requires more than enabling a new interface. As shown in this guide, Studio depends on a set of supporting services and bundles that work together to provide search, background processing, and real-time updates.
Once these components are correctly set up, Studio UI becomes fully operational and ready for everyday use. From that point on, teams can start working with Pimcore through a modern interface, while developers gain access to a more structured and maintainable foundation for further customization.
If you are planning a broader transition from the Classic Admin UI, this setup is only the first step. Understanding how Studio changes daily work, how to extend it, and how to approach migration should be considered next.