Shopware plugins

Shopware plugins and apps: build, adapt, keep them ready for updates

Two situations lead to this page. Either your Shopware 6 shop is missing a function that the standard system does not provide — or an existing extension is blocking the update. Both are development work, not an operations topic. Sharpness Solutions GmbH in Oldenburg develops Shopware plugins and apps, adapts store extensions, ports your own code from 6.6 to 6.7 and takes over third-party extensions when the vendor no longer delivers. The current version is Shopware 6.7; Shopware 6.8 is expected in 2027. This page was last updated on 17 August 2026. Telephone 0441 21 21 63 0, Mon–Fri 9:00–16:00.

Make an enquiry 0441 21 21 63 0 Mo – Fr, 9:00 – 16:00 Uhr

What shop operators come to us with

Enquiries about Shopware extensions rarely arrive with a specification. They arrive with a sentence like „there must be some way to do this" or with the error message from a failed update attempt. The four cases below cover most of them. What they have in common is that the real decision is made before the first line of code: buy, adapt or build — and whether the result becomes a plugin or an app. Anyone who skips this decision pays for it at the next major release.

The store has nothing that really fits

You have searched the Shopware Store and found three extensions, each of which covers a third of your requirement. Installing all three is more expensive than your own solution and much harder to maintain, because you then have three vendor roadmaps in your deployment. Before we build anything, we check whether one of the three is enough with an adaptation. That is the smaller job, and often the right one.

A plugin is blocking the update to 6.7

Either the extension's Composer constraint does not allow shopware/core in version 6.7, or the update runs through and the administration stays white. Shopware 6.7 has removed the Vue 2 compatibility layer and builds the administration with Vite instead of Webpack. Extensions that build on this need their own 6.7 release with newly built assets — not just a relaxed constraint in composer.json.

The vendor no longer delivers

The plugin works, but the last version dates from the 6.5 period, there is no 6.7 version in the store, and nobody answers enquiries. The function sits in your shop, but the decisions about it sit with somebody else. The way out is replacement, a fork or new development. Which of these is open to you is decided first by a look at the licence and then by a look at the code — not the other way round.

The old plugin writes into the core

At some point somebody changed a core file, copied a storefront template instead of extending it, added a column to a core table with ALTER TABLE, or worked around a class marked as final. That works until the next major release and not after it. A plugin that blocks an update is a construction fault, not fate. It can be repaired, but not as a side task on the day of the update.

The three ways: buy, adapt, build yourself

The first way is the Shopware Store, and it is the right one when an extension essentially matches your requirement. For payment methods, shipping providers, review systems, invoice layouts or marketplace integrations there are well-maintained standard solutions, and building your own alongside them would be a waste. Two things belong in the calculation. First: since 28 December 2023 the rental licence is the only way to acquire an extension licence in the Shopware Store. When the rental period ends, the right to use the extension ends — that is a running item in your operating budget, not a one-off investment. Second: you take on the vendor's roadmap. Whether there is a compatible version when Shopware 6.8 is released is decided by the vendor, not by you. If a store extension covers your requirement, we say so, even though we then develop nothing.

The second way is adapting an existing extension, and it is regularly overlooked. The source code is readable: PHP and Twig in any case, and the quality guidelines for the Shopware Store require the uncompiled version of the JavaScript to be shipped in a separate directory. Adapting still does not mean editing inside somebody else's plugin — everything would be gone again with the next vendor update. We build a second, small plugin alongside it: it decorates the services of the third-party extension, hooks into its events, extends its Twig templates via sw_extends and, in the admin, overrides only the components it has to change. Both extensions remain separately updatable. The limit of this approach is sharp: if the third-party extension offers no extension points, hides its logic in final classes or private methods and sets no useful blocks in its templates, the approach ends there. We see this in advance, not in the middle of the project.

The third way is your own development. It is almost always the most expensive to buy and rarely the wrong choice over the lifetime of the system. You get exactly the function your process needs, no configuration screen for thirty cases you do not have, and no third-party logic in the request path of the checkout. No right of use that ends with a cancellation. In return you carry the maintenance yourself: every major step in Shopware costs adaptation, and that adaptation is then on your invoice. We compare both ways against each other if you ask us to, and the figure that counts is not the quoted price but the total over the years you intend to run the system. And some requirements are not plugin requirements at all: a plugin that automates an unclear rule makes the lack of clarity faster, not better.

Plugin or app: the difference that remains

A plugin is PHP code that runs inside the Shopware process itself. Technically it is a Composer package with a plugin base class and a lifecycle of install, activate, update, deactivate and uninstall. It has access to everything Shopware and Symfony provide: event subscribers, service decoration through the container, its own EntityDefinition and extensions of existing entities, its own storefront and admin routes, Twig overrides, its own admin components, scheduled tasks and message handlers. The price for this is dependency: a plugin can only be run in a self-hosted installation, not in Shopware Cloud. And it sits in the request path. Whatever time it uses there, the shop uses on every request.

An app brings no executable code into the shop, only a manifest.xml. The logic runs on its own app server, which talks to the shop through the Admin API, the Store API and webhooks — in a language of your choice. Apps run in Shopware Cloud and in self-hosted installations. For logic that has to happen inside the shop process there are App Scripts: Twig files that, since Shopware 6.4.8.0, are executed in a sandbox at defined hooks and see only the services that the respective hook provides. An app extends the administration through the Meteor Admin SDK; the interface comes from an iframe and communicates via postMessage. Your own data structures go through a Resources/entities.xml; the entity names usually carry the prefix ce_, which is possible and recommended since Shopware 6.4.15.0 because the full names fail at the length limits of the database. After that they appear as a regular entity in the Admin API and in the administration.

The decision is unspectacular. An app, if Shopware Cloud is involved, if the logic lives outside anyway — a price calculation in the ERP, an availability service, a middle layer to a third-party system — or if you want to deliver the extension to several shops. A plugin, if the work reaches deep into the data model, the storefront or the checkout, if latency matters, or if the function has to run without a network connection to the outside. Both disadvantages should be stated. The app server is a second system that you have to run, monitor and keep up to date — if it stops, the function stops. The plugin, on the other hand, lives in the shop's deployment and needs your attention at every major release. There is no option here without follow-up costs, only two different ones.

Developing to the standard so the next update is not blocked

Shopware promises extension developers backward compatibility, and this promise is pleasantly concrete. Public and protected methods, properties and constants count as public API, and so do interfaces and abstract classes, the constructors of DTOs such as CalculatedPrice or QuantityPriceDefinition, Twig templates and blocks of the storefront, the JavaScript plugins and services, the props, slots and events of the admin components, and CSS selectors with structural meaning. Breaking changes are only allowed in major releases; before that, the affected code is marked with an annotation such as @deprecated tag:v6.8.0, which names the target release and the replacement. Anyone who reads these annotations knows months before the major release what has to be done. There are two exceptions you have to know. First: the constructor of a service that is instantiated by the container is explicitly not public API and may change at any time — anyone who creates such a service themselves with new instead of decorating it builds in the blockage. Second: private methods, properties and constants are not covered, and neither is anything marked @internal or @experimental. A class marked as final, by contrast, is part of the public API — it may be used, only not inherited from. The plugins that block updates later sit at these edges.

In practice this comes down to a short list. Do not touch a core file — the quality guidelines for store extensions forbid changes to core files and core database tables in any case. Event subscribers instead of copied logic. Service decoration instead of replacing classes. Entity extension instead of ALTER TABLE. Twig extension with sw_extends and targeted block overrides instead of a copied template that quietly falls apart at the next storefront rebuild. In the admin, the intended override API instead of replacing files. Plus the things that show up later in operation: an uninstall routine that takes its data with it, snippets with a fallback language, proper logging instead of output into nowhere, and migrations that run a second time without doing damage.

Checking is cheaper than hoping, and Shopware supplies the tools itself. shopware-cli extension validate checks metadata, packaging, directory structure, snippets and PHP syntax at the basic level; with --full it adds PHPStan, ESLint, Stylelint and separate checks for admin and storefront Twig, each of which can be switched on individually via --only and --exclude. With --check-against lowest or highest, the check runs against the edges of your version constraint, and that is exactly where plugins break. extension format and extension fix clean up what can be cleaned up automatically; underneath, PHP CS Fixer, Prettier, Rector for PHP and ESLint for JavaScript do the work. The former Extension Verifier, a separate Docker image with the commands check, format and fix, was merged into shopware-cli in May 2025 — its repository is archived, and its checks sit in the commands above. So there are not two tools, only one. With us it runs in the CI, not on the laptop of one individual. But a linter does not find a mistake in reasoning. A plugin that follows every rule and solves the wrong problem is still wrong.

The break with 6.7: two lines, two releases

Shopware 6.7 is the biggest technical rebuild since Shopware 6 started, and it hits the administration hardest. Vue 3 instead of Vue 2 — the compatibility layer is removed, not deprecated. Vite instead of Webpack, so a webpack.config.js becomes a vite.config.js and the delivered build artefacts look different. Pinia instead of Vuex: the core stores are located under Shopware.Store instead of Shopware.State, and the old Vuex helpers only continue to exist under new names — mapState is now mapVuexState, mapMutations is mapVuexMutations, mapGetters is mapVuexGetters, mapActions is mapVuexActions. You can still create your own Vuex stores; it is not recommended. On top of that comes the move to the Meteor Component Library, in which sw-button becomes mt-button and the v-model bindings change. For you this means one thing: a 6.7 release of an extension is a separate package with its own build, not an adjusted version number.

The remaining edges sit in the PHP part and in the storefront. The core classes have been given native types on their properties throughout; every class that inherits from them has to follow with the types. Payment processing runs through a single AbstractPaymentHandler class that replaces five interfaces: AsyncPaymentHandlerInterface, SyncPaymentHandlerInterface, PreparedPaymentHandlerInterface, RefundPaymentHandlerInterface and RecurringPaymentHandlerInterface; a handler now only receives orderTransactionId, the request data as far as it is present, and the context. Payment and shipping methods need a technicalName, mandatory in the API and in the database — the technical_name column becomes non-nullable in payment_method and shipping_method. Custom field and fieldset names may no longer contain hyphens or dots; they have to be valid Twig variable names. Header and footer load via ESI through their own routes /header and /footer. Store API route caching has been dropped, and with it the Cached*Route classes. And for plugins the route via a Resources/config/entities.xml is gone — custom entities via XML have been removed for plugins; what belongs there now is your own EntityDefinition or attribute-based entities.

Anyone maintaining an extension for 6.6 and 6.7 at the same time maintains two lines: two branches, two CI runs, two test matrices and, in the store, two version states under one entry. The effort for this is closer to a major step than to a point release, and that is not an argument against 6.7 but a planning figure. For existing installations it has been much more relaxed since the beginning of 2026: the large store plugins have compatible versions, unlike in the first months after the release. Anyone who runs only their own shop does not need the second line anyway — then we port once to 6.7 and close 6.6. The update project itself, meaning the order of steps, the staging run and the rollback plan, has its own page; here we are talking about the code that has to move with it.

Orphaned plugins and taking over third-party code

When a vendor no longer delivers there are three ways forward, and the first look does not go into the code but into the licence. With a rental licence from the Shopware Store, the right of use ends with the rental period; whether you may then fork the code, develop it further or run it at all is first a legal question and only then a technical one. That is answered by your legal advisers, not by your agency. If the extension is available as open source on Packagist or GitHub, a fork is the shortest way: your own repository, your own constraint, your own release responsibility. The second way is replacement with a maintained alternative, even if configuration and data have to be moved in the process. The third is new development — and it has an underestimated advantage: the specification already exists, and it has been running in your shop for years.

Before we agree to a takeover we look at the same set of questions, every time. What is in the composer.json, in particular in the constraint against shopware/core and in the dependencies? Is there a regular plugin base class and a clean lifecycle, or does the installation happen in a migration? What does the uninstall leave behind? How many services are decorated, and does one of these decorations reach into internals that are marked @internal or count as private? Are storefront templates extended via sw_extends or copied? Do the overridden admin components still use Vue 2 patterns or Shopware.State? Do tests exist, and do they run? Plus a run of shopware-cli extension validate --full against the edges of the constraint and, where it makes sense, extension format and extension fix. This is work of hours to days, not minutes, and it is a defined first deliverable with its own price.

At the end there is a findings report: porting effort by area of work, a risk list with priorities and, next to it, the alternative of new development with its own figure. Both figures stand side by side, even if porting is the smaller job. And we decline if a plugin is built in such a way that we cannot vouch for its behaviour after the next update. An extension that reaches into undocumented internals in five places is not a porting case but a new development with an existing specification — and then it is more honest to call it that than to offer a port that has to be paid for a second time at the next major release. A commitment without a look at the code would be guesswork, and guessing is not a method with somebody else's code.

Process

Send us the requirement or the plugin list.

If a function is missing, describe the process it should replace. If a plugin is blocking the update, the output of composer show or the list from the extension management is enough. You get a written assessment with a recommended way forward, an effort range and the alternative next to it — even when we recommend a store extension and develop nothing. Sharpness Solutions GmbH, Edewechter Landstraße 161, 26131 Oldenburg. Telephone 0441 21 21 63 0, Mon–Fri 9:00–16:00, info@sharpness.de.

  1. 01

    Sharpening the requirement

    First we clarify what exactly should happen and at which point in the process — not which technology is used. Who solves the problem manually today, and how? What is the rule that should be automated, and does it apply without exception? Unclear rules produce expensive plugins.

  2. 02

    Store research and feasibility

    We review the Shopware Store and Packagist for existing solutions and check, for any candidates, whether they offer extension points or close off their logic. In parallel we check which hooks, events and services Shopware provides for your requirement at all. The result is a short list of realistic ways forward.

  3. 03

    Decision and scope

    Buy, adapt or build — and plugin or app. Plus the scope: what belongs in the extension, what belongs in the configuration, what stays manual work in day-to-day business. You get an effort estimate by area of work, a fixed price for clearly defined parts, and a named list of what can only be decided on the test system.

  4. 04

    Development against extension points

    The work happens in a Git repository that belongs to you, against a staging installation, not in live operation. Event subscribers, service decoration, entity extension and sw_extends instead of core changes. shopware-cli extension validate --full runs in the CI with every commit, checked against both edges of the constraint.

  5. 05

    Acceptance, update test, deployment

    Before acceptance there is an update test: installation, activation, uninstallation and a patch step of the shop with the extension active. You test against an acceptance list. The deployment goes through the agreed route with a backup and a documented way back, not through the plugin management in the browser.

  6. 06

    Maintenance across version boundaries

    After that comes the question of who brings the extension up to date at coming releases. We watch the @deprecated markers with their target release and report early what will be due for Shopware 6.8. If you hand over the maintenance, it runs through the service level tiers: BASIC 24, STANDARD 8, ADVANCED 4, PREMIUM 2 hours response time, monthly flat rate net per shop.

Projects on this system

A selection — not the full client list.

Frequently asked questions

What does developing a Shopware plugin cost?

A Shopware plugin is calculated by effort, and the effort is determined by four factors: how many points in the Shopware process the extension reaches into, whether it adds its own data structures, whether the administration is extended, and whether an interface to the outside is part of it. An extension that catches one event and fills one field is a different item from one that touches the checkout and the price calculation. A reliable figure exists after the requirement has been clarified, not in the first phone call. For clearly defined parts we work at a fixed price.

Buy a store plugin or have one developed?

If a store extension essentially matches your requirement, buying is cheaper — even though we then develop nothing. Two points belong in the comparison. Since 28 December 2023 the rental licence is the only way to acquire an extension licence in the Shopware Store; when the rental period ends, the right of use ends. And compatibility with coming major versions is decided by the vendor. Your own development costs more to buy and moves the maintenance to you. The comparison is therefore made over the lifetime, not over the quoted price.

What is the difference between a plugin and an app in Shopware 6?

A plugin is PHP code that runs inside the Shopware process itself: a Composer package with a plugin base class and a lifecycle, with access to events, services, the data model, templates and the administration. It requires a self-hosted installation. An app brings only a manifest.xml into the shop; its logic runs on its own server and talks to the shop through the Admin API, the Store API and webhooks. Apps also run in Shopware Cloud. For logic inside the shop process, apps have App Scripts: Twig in a sandbox, at defined hooks, since Shopware 6.4.8.0.

Can we use a plugin in Shopware Cloud?

No. Classic plugins require a self-hosted installation because they execute PHP code inside the Shopware process. In Shopware Cloud only the app system works: manifest.xml, your own app server, the Admin API and the Store API, webhooks, App Scripts and admin interfaces through the Meteor Admin SDK. That is not a step backwards, but a different division of the work: whatever has to happen deep in the data model or in the checkout needs either a hook with an App Script, or it is not possible. Which variant you run is something we clarify before the effort estimate.

Why does a plugin block the update to Shopware 6.7?

Usually for one of two reasons. Either the extension's constraint against shopware/core does not allow the 6.7 line — then Composer stops the update, which is the friendly case. Or the update runs through and the administration stays white, because the extension relies on Vue 2 patterns, on Shopware.State or on a Webpack build. Shopware 6.7 has removed the Vue 2 compatibility layer and builds with Vite; the core stores are in Pinia under Shopware.Store, and the old Vuex helpers are now called mapVuexState, mapVuexMutations, mapVuexGetters and mapVuexActions. A relaxed constraint does not help then: it needs its own 6.7 release with newly built assets.

Do we have to maintain separate plugin versions for Shopware 6.6 and 6.7?

Yes, if the extension is to run in both lines. In 6.7 the administration is built with Vite, in 6.6 with Webpack; the delivered build artefacts are not the same. So you need two branches, two builds, two test matrices and, in the store, two version states under one entry. The effort is closer to a major step than to a point release. If you only run the extension in your own shop, the second line is unnecessary: then we port once to 6.7 and close 6.6.

What exactly has to be changed in a plugin for Shopware 6.7?

In the administration: Vue 3 syntax, the core stores via Shopware.Store instead of Shopware.State — the old Vuex helpers are now called mapVuexState, mapVuexMutations, mapVuexGetters and mapVuexActions —, a vite.config.js instead of webpack.config.js and the move to the Meteor Component Library, in which sw-button becomes mt-button. In the PHP part: native types on inherited properties, payment processing through AbstractPaymentHandler instead of the five old handler interfaces, a technicalName on payment and shipping methods, custom field names without hyphens and dots, a replacement for the Cached*Route classes that have been dropped, and, for custom entities, your own EntityDefinition instead of the removed entities.xml. In the storefront: header and footer load via ESI through their own routes.

Do you also adapt an extension from the Shopware Store?

Yes, but not by editing inside somebody else's plugin — that would be lost with the next vendor update. We build our own small extension alongside it, which decorates the services of the store extension, hooks into its events and extends its templates via sw_extends. Both remain separately updatable. We check the limit in advance: if the store extension offers no extension points, keeps its logic in final classes and sets no useful Twig blocks, we say so before you place the order.

What can we do if the plugin vendor no longer delivers?

There are three ways forward: replacement with a maintained alternative, taking over the code as a fork, or new development of the function. The first look goes into the licence, not into the code: with a rental licence the right of use ends with the rental period, and whether a fork is permitted is answered by your legal advisers. If the extension is available as open source, a fork is the shortest way — your own repository, your own constraint, your own release responsibility. New development has an advantage that is often overlooked: the specification has been running in your shop for years.

Do you take over a plugin that another agency developed?

Yes, but only after a look at the code. We look at composer.json and the constraint, the lifecycle, the migrations and what the uninstall leaves behind, the service decorations including access to internals, whether templates are extended via sw_extends or copied, whether overridden admin components still use Vue 2 patterns, and whether tests exist and run. Plus a run of shopware-cli extension validate --full against both edges of the constraint. The result is a findings report with the porting effort and the alternative of new development next to it. Sometimes we decline — that is more honest than a port that gets paid for twice.

How do you make sure an extension stays ready for updates?

By limiting ourselves to what Shopware promises as public API: public and protected methods and properties, interfaces and abstract classes, the constructors of DTOs, Twig blocks of the storefront, JavaScript plugins, props and events of the admin components. Not covered are private methods and everything marked @internal or @experimental — that is where the blockages come from. The constructor of a container service is not covered either: it may change at any time, which is why a service is decorated and not instantiated by hand. A final class, by contrast, is public API, only not meant to be inherited from. Plus the tools: shopware-cli extension validate --full in the CI, checked against the edges of the constraint, together with extension format and extension fix, which contain the checks of the former Extension Verifier. And we read the @deprecated markers that name the target release.

Does our extension belong in the Shopware Store?

Only if you want to sell it or provide it to several shops. For an extension that serves exactly one shop, the store is extra effort without a return: quality guidelines are added, an automatic code review with PHPStan and SonarQube, the uncompiled version of the JavaScript in a separate directory, snippet translations with a fallback, an uninstall routine that cleans up its data, a production build within the store's size limit and traceable dependencies. For a product that is worth it. For your internal plugin the code is better placed in your own repository, versioned and without an approval cycle.

Who maintains the extension after acceptance?

You decide that, and we put it in writing. The code is in your repository and the documentation is part of the delivery — a handover to your own team is therefore possible at any time. If we take over the maintenance, it runs through the service level tiers: BASIC 24 hours, STANDARD 8 hours, ADVANCED 4 hours, PREMIUM 2 hours response time, as a monthly flat rate net per shop. Without such an agreement our basic commitment applies: processing in order of arrival within 48 hours during business hours, Mon–Fri 9:00–16:00.

Enquiry

Which function is missing — or which plugin is stuck?

Describe briefly what the extension should do, or which existing one is in your way. If you are not sure whether something suitable already exists in the store: we check that as well, and if it does, we say so.

  • An answer from someone who knows the system — no phone queue
  • An assessment before the quote, even when it advises against the project
  • Your details are sent to us by email, not into a third-party CRM

Spam protection: Cloudflare Turnstile — no cookies, no tracking.

Call Start a project