Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

alireza_hadizadeh's avatar

How to handle GitHub for project with multiple customers

Hello everyone,

At the company where I work, we have a project that functions like a shop, which we sell to multiple customers. Each customer has a unique UI and specific features. Sometimes, we work on features that need to be applied to all customers, and sometimes only to some.

Currently, we manage this with a single repository named "Shop" and maintain different branches for each customer.

My question is: Should we continue with this approach, or would it be better to create a base repository and then fork a repository for each customer?

0 likes
5 replies
pluma's avatar

How unique is the UI for each customer? Would it be possible to unify the branches and apply different UIs based on configuration like different themes? Customer-specific features are an age old problem. The best solution in my experience (>10 years) is to introduce feature flags, i.e. configuration settings which can be turned on or off for different customers to customize their version of the software.

On GitHub forks are just repositories with a base branch that is downstream from the forked origin. If you want to give customers access to "their" branch, a fork might be a way to do that (but be careful not to leak info about other customers and beware of secrets). Otherwise it is probably overkill.

1 like
martinbean's avatar

@alireza_hadizadeh Branches is not really the solution. You should be deploying from a single branch (i.e. main) rather than having different branches for different clients, as that’s just not maintainable.

I have a similar project: a multi-tenant CMS that hosts websites for multiple clients. A bit like a small Wix or Squarespace. There’s a single codebase, but then each customer has their own “website” with its own pages, design, etc.

I tackled this by having “base” templates and then defining a Blade view namespace in middleware which searches two paths for Blade templates: a website-specific template, before falling back to the “global” templates:

class DefineViewNamespace
{
    public function handle(Request $request, Closure $next)
    {
        // Get website from route-model binding
        $website = $request->route('website');

        View::addNamespace('website', [
            resource_path(sprintf('vendor/%s', $website->slug)), // Website-specific path
            resource_path('views/website'),
        ]);

        return $next($request);
    }
}

So this will look for a website-specific template in resources/views/vendor/{website slug} and if a template isn’t found, fall back to looking in the resources/views/website directory. It means I can then define overrides on a per website basis.

I also make heavy use of feature flags as @pluma suggests. For example, some websites have a shop and others don’t. So I can use feature flags (powered by Pennant) to conditionally show shop-related things such as navigation items:

<li>
    <a href="{{ route('website.home', compact('website')) }}">
        {{ __('Home') }}
    </a>
</li>
@feature('shop')
    <li>
        <a href="{{ route('website.shop.home', compact('website')) }}">
            {{ __('Shop') }}
        </a>
    </li>
@endfeature
1 like
Ben Taylor's avatar

I also have a multi Tennant app, with multiple websites sharing the same code base. I handle it slightly differently. Customers can create whatever pages they want. Pages are made up of components. The empty html for each component is hard coded either as blade or Vue components. But the styles and content for each component are totally dynamic, allowing for a fully customised website for each customer.

Please or to participate in this conversation.