Building custom extensions for Shopware should never feel like reinventing the wheel. With version 6.7 rolling out stricter type safety, deeper Symfony integration, and fully modernized extension lifecycles, the gap between a concept and a production-ready plugin has narrowed—but only if you start with the right foundation. This is where a well-crafted plugin boilerplate becomes indispensable. Instead of manually wiring dependencies, hunting down deprecated service tags, or guessing how admin assets should compile, developers can clone, configure, and extend a modern scaffold that respects Shopware 6.7’s architectural shifts. In this guide, we’ll walk through what makes a 6.7-compatible boilerplate essential, how its pieces interact under the hood, and why starting here saves hours of debugging before you write your first business rule or Vue component.

Why 6.7 Changes Demand a Modern Scaffold

Shopware 6.7 isn’t just a version bump; it’s a quiet but decisive refactor of the extension ecosystem. The platform now mandates PHP 8.3+, enforces stricter container definitions, and has officially deprecated several legacy service registration patterns. Symfony 7.x integration means dependency injection relies heavily on attributes over verbose XML configuration. The plugin manifest structure has been streamlined, and CLI command discovery no longer requires manual routing hacks—PHP attributes handle registration automatically during kernel boot.

Perhaps most importantly, the administration stack has fully migrated to Vue 3 with TypeScript-first tooling, while storefront integrations now expect route isolation and strict security boundaries. A boilerplate built for 6.7+ doesn’t just “work”; it aligns with how the platform expects extensions to behave under the hood, preventing upgrade friction and runtime container warnings down the line.

The Anatomy of a 6.7-Ready Plugin Scaffold

A production-ready boilerplate follows a predictable directory layout that maps directly to Shopware’s boot lifecycle. The structure enforces separation of concerns while remaining intuitive for developers familiar with modern Symfony practices:

src/
├── Core/          # Framework-agnostic logic, repositories, DTOs
├── Storefront/    # Controllers, route config, Twig templates
├── Administration/# Vue 3 components, TypeScript interfaces, admin routes
├── Migration/     # Versioned database schema changes
├── Services/      # Business logic, API clients, external integrations
└── {YourPlugin}.php # Entry point & KernelPluginBoot implementation

Every directory serves a purpose. src/Core/ holds reusable, environment-agnostic classes. src/Storefront/ manages request/response flows while respecting Shopware’s security and caching layers. src/Administration/ bundles precompiled assets ready for the plugin manager, complete with proper module registration. Migrations stay isolated to guarantee idempotent schema updates, while Services/ acts as the container for third-party clients or custom business rules. This separation isn’t cosmetic—it ensures your extension remains testable, upgrade-safe, and compliant with Shopware’s module boundaries.

Wiring Services & Commands the 6.7 Way

In earlier versions, registering a custom service meant editing multiple XML files and hoping tags matched. Shopware 6.7 shifts this entirely toward PHP attributes and explicit container definitions. Modern plugins rely on Symfony’s autoconfigure behavior combined with targeted tags. A typical 6.7-compliant service looks like this:

declare(strict_types=1);

namespace YourVendor\YourPlugin\Services;

use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;

#[AsTaggedItem('shopware.data_abstraction_layer.entity_repository')]
class CustomProductAccessor extends EntityRepository 
{
    public function __construct(private readonly string $entityName) {}

    public function search(Criteria $criteria): array
    {
        // Business logic without XML boilerplate
        return parent::search($criteria)->getEntities()->getData();
    }
}

The container infers registration based on declared interfaces and tags. CLI commands follow the same pattern: apply Symfony’s #[AsCommand] attribute, and the plugin boot process discovers them during kernel initialization. No more manual routing tricks or deprecated subscriber registrations—just clean, type-safe definitions that survive composer updates and cache warmups.

Admin Extensions & Storefront Integration

Modern Shopware expects extensions to communicate through typed APIs and component-based UI layers. A 6.7 boilerplate pre-configures Vite to compile Vue 3 components into the administration bundle, while automatically injecting necessary TypeScript interfaces for your custom entities. In administration/index.ts, module registration is simplified:

import { Module } from '@shopware-ag/admin-sdk';

Module.register('your-plugin-module', {
  title: 'Your Plugin',
  subtitle: 'Manage custom configurations',
  routes: import.meta.glob('./pages/**/*.vue'),
});

On the storefront side, the scaffold includes a base controller template that respects Shopware’s security checks, route annotations, and Twig namespace registration. You won’t manually copy assets or register event subscribers anymore—the layout hooks into Shopware\Core\Framework\Plugin\KernelPluginBoot to handle lifecycle events safely. This means your extension starts in active state without triggering deprecated boot warnings, and your storefront routes resolve correctly across environments.

Built-In Guardrails for Ship-Ready Code

Beyond structure, a true boilerplate enforces quality from day one. It ships with PHPUnit and Jest preconfigured for controller and component testing, along with PHPStan rules aligned to Shopware’s static analysis standards. Composer dependencies are pinned to 6.7-compatible versions, preventing version drift during local development. The manifest includes proper metadata fields that comply with current plugin marketplace requirements.

More importantly, it isolates custom configurations in environment-aware files, ensuring your plugin doesn’t leak production secrets or break across PHP versions. When you clone it, configure one namespace variable, and run the administration build script, you’re already 80% of the way to a deployable extension.

Conclusion

Starting every Shopware extension from scratch is no longer a rite of passage—it’s an avoidable bottleneck. A 6.7-ready plugin boilerplate encapsulates years of framework evolution into a single, maintainable repository. It respects modern PHP standards, leverages Symfony’s full DI capabilities, and aligns with how Shopware expects extensions to interact under the hood. Whether you’re building a payment provider, a complex checkout step, or a custom admin dashboard, this foundation lets you ship faster, debug less, and stay compliant with future core updates. Grab a 6.7-compatible scaffold, configure your namespace, and start solving actual business problems instead of wiring containers.