Private Magento Composer Package Repository Guide
Private Magento Composer Package Repository Guide
This guide explains how Example Development creates, publishes, versions, and distributes proprietary Magento 2 modules using a self-hosted GitLab Composer Package Registry.
The examples use a fictional Magento module named Example_Core, published as the Composer package example/module-core.
- GitLab Server: https://git.example.com
- GitLab Group: example-magento
- GitLab Repository: module-core
- Project ID: 123
- Composer Package: example/module-core
- Initial Version: 1.0.0
1. Create the Repository
1.1 Create the GitLab Group
- Log in to https://git.example.com.
- Navigate to Groups and create a new group.
- Set the group name to Example Magento.
- Set the group path to example-magento.
- Set visibility to Private.
All reusable Magento modules should be maintained in this group. Each module should have its own GitLab repository.
1.2 Create the Module Repository
- Open the example-magento group.
- Select New project.
- Create a blank project named module-core.
- Set visibility to Private.
- Create the project.
Repository URL:
https://git.example.com/example-magento/module-core.gitIn this example, the project ID is 123. Replace it with the actual numeric ID assigned by GitLab.
1.3 Clone the Repository
git clone https://git.example.com/example-magento/module-core.git
cd module-coreCopy the contents of the Magento module into the repository root. Do not copy the entire app/code/Example/Core directory hierarchy.
Expected repository structure:
module-core/
composer.json
registration.php
etc/
Helper/
view/
.gitignore1.4 Create composer.json
Every Composer package must contain a composer.json file. The package name follows the format vendor/package-name.
Example:
{
"name": "example/module-core",
"description": "Example Core Module for Magento 2",
"type": "magento2-module",
"license": "proprietary",
"authors": [
{
"name": "Example Development",
"homepage": "https://www.example.com/"
}
],
"require": {},
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Example\\Core\\": ""
}
}
}The Magento registration.php file must register the Example_Core module, and etc/module.xml must declare the same module name.
1.5 Define PHP Version Requirements
Composer allows packages to specify supported PHP versions through the require section.
Require PHP 8.2 specifically:
"require": {
"php": ">=8.2 <8.3"
}Allow PHP 8.2 and PHP 8.3:
"require": {
"php": ">=8.2 <8.4"
}Allow PHP 8.1 and later compatible versions below PHP 9:
"require": {
"php": "^8.1"
}Composer checks these requirements during installation and updates. If the server's PHP version does not satisfy the requirement, dependency resolution fails.
PHP version constraints must reflect the versions actually supported and tested by the module and its Magento dependencies.
1.6 Add Dependencies Between Modules
Suppose Example_Integration requires Example_Core. Add the following dependency to the integration module's composer.json file.
{
"name": "example/module-integration",
"description": "Example Magento Integration Module",
"type": "magento2-module",
"license": "proprietary",
"require": {
"php": ">=8.2 <8.4",
"example/module-core": "^1.0"
},
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Example\\Integration\\": ""
}
}
}With this dependency, installing example/module-integration automatically installs example/module-core when required.
composer require example/module-integrationThe version constraint ^1.0 allows compatible releases starting at 1.0.0 but excludes version 2.0.0 and higher.
1.7 Create .gitignore
Create a .gitignore file to prevent operating-system files, editor configurations, credentials, and temporary files from being committed.
# macOS
.DS_Store
._*
.AppleDouble
.Spotlight-V100
.Trashes
# Windows
Thumbs.db
Desktop.ini
# IDEs
.idea/
.vscode/
*.iml
*.swp
*.swo
# Composer
/vendor/
auth.json
# Secrets
.env
.env.*
!.env.example
*.pem
*.key
# Temporary files
*.log
*.tmp
*.bak
# Testing
.phpunit.cache/
/coverage/
# macOS archives
__MACOSX/Remove unwanted macOS metadata files:
find . -path './.git' -prune -o -name '.DS_Store' -type f -delete
find . -path './.git' -prune -o -name '._*' -type f -delete1.8 Validate and Push the Repository
Validate the Composer configuration:
composer validate --no-check-publishCommit and push the source code:
git add .
git commit -m "Initial release of Example_Core"
git push -u origin HEADThe source code is now stored in GitLab. Pushing the source code does not automatically publish a Composer package.
2. Configure the Package Registry and Access Tokens
2.1 Verify the GitLab Package Registry
- Open the module-core GitLab project.
- Navigate to Deploy > Package Registry.
- Verify that the Package Registry is available.
Initially, the registry may display no packages. Packages appear after publishing through the Composer API.
2.2 Create the Publisher Deploy Token
The publisher credential is used internally to publish new package versions.
- Open the example-magento GitLab group.
- Navigate to Settings > Repository > Deploy tokens.
- Create a group deploy token.
- Configure the following settings.
- Name: Example Composer Publisher
- Username: example-composer-publisher
- Permission: write_package_registry
- Expiration: According to the organization's security policy
Save the generated username and token securely. Do not commit credentials to Git or share publisher credentials with customers.
2.3 Enter Publisher Credentials on macOS
These commands use the default macOS Zsh shell.
read "GITLAB_USER?GitLab deploy token username: "
read -s "GITLAB_TOKEN?GitLab deploy token: "
echoGITLAB_USER stores the deploy token username. GITLAB_TOKEN stores the secret. The secret is hidden while being entered.
2.4 Create the Initial Version Tag
git tag -a 1.0.0 -m "Example_Core version 1.0.0"
git push origin 1.0.0A tag identifies a specific version of the source code. Unlike the main branch, a release tag should not move.
2.5 Publish the Initial Composer Package
Publish version 1.0.0 using the GitLab Composer API.
curl --request POST \
--user "$GITLAB_USER:$GITLAB_TOKEN" \
--data-urlencode "tag=1.0.0" \
--write-out "\nHTTP Status: %{http_code}\n" \
"https://git.example.com/api/v4/projects/123/packages/composer"Expected successful response:
{"message":"201 Created"}
HTTP Status: 201The package example/module-core version 1.0.0 is now published in the private Composer Package Registry.
2.6 Verify the Published Package
Open the GitLab project's Package Registry and verify:
- Package: example/module-core
- Version: 1.0.0
- Type: Composer
Verify package metadata through the API:
curl --user "$GITLAB_USER:$GITLAB_TOKEN" \
--write-out "\nHTTP Status: %{http_code}\n" \
"https://git.example.com/api/v4/group/example-magento/-/packages/composer/p2/example/module-core.json"A successful response returns HTTP 200 and the package metadata.
2.7 Create a Customer Deploy Token
Each customer should receive a separate read-only credential. Customers must not receive the publisher token.
- Open the example-magento GitLab group.
- Navigate to Settings > Repository > Deploy tokens.
- Create a new token for the customer.
- Enable only read_package_registry.
- Save the generated username and secret.
Example customer token:
- Name: Demo Customer
- Username: example-demo-customer
- Permission: read_package_registry
- Publishing permissions: Disabled
- Repository permissions: Disabled
Important: A group deploy token can access package registry resources across the group. It does not enforce per-package customer licensing. Package-specific entitlements require a different access structure or a dedicated distribution service.
2.8 Configure the Customer Composer Repository
Navigate to the customer's Magento project root, where composer.json is located.
composer config repositories.example composer \
https://git.example.com/api/v4/group/example-magento/-/packages/composer/This adds the private Composer repository to the customer's composer.json file.
2.9 Configure Customer Authentication
composer config --auth http-basic.git.example.com example-demo-customerEnter the generated customer deploy token when prompted. Composer stores the credentials in its authentication configuration.
Keep auth.json private and excluded from source control.
2.10 Install the Package
Install the core module:
composer require "example/module-core:^1.0"Composer retrieves the metadata, downloads the package archive, and installs a compatible version.
If the module is being installed into Magento, enable it after Composer installation:
php bin/magento module:enable Example_Core
php bin/magento setup:upgrade
php bin/magento cache:flushPerform installation and upgrade testing on staging before deploying changes to production.
2.11 Customer Token Security
- Create separate credentials for each customer.
- Use read_package_registry for customer credentials.
- Keep publisher credentials internal.
- Set expiration dates and rotate tokens regularly.
- Revoke compromised or unused tokens.
- Never store credentials in source control.
3. How to Push a New Version
3.1 Versioning Strategy
Use semantic versioning for Composer packages.
- 1.0.0: Initial stable release.
- 1.0.1: Bug fixes.
- 1.1.0: Backward-compatible new features.
- 2.0.0: Breaking changes.
The main branch contains ongoing development. Git tags identify specific published releases.
3.2 Update the Source Code
Open the local repository:
cd module-core
git checkout main
git pull --ff-only origin mainMake the required changes to the Magento module. Update composer.json if PHP requirements or package dependencies have changed.
3.3 Change PHP Requirements
Example: A future release supports PHP 8.3 and 8.4.
"require": {
"php": ">=8.3 <8.5"
}This permits PHP 8.3 and 8.4 but excludes PHP 8.2 and 8.5. Use only requirements that match tested compatibility.
3.4 Update Package Dependencies
Suppose Example_Integration now requires Example_Core version 1.2.0 or newer.
"require": {
"php": ">=8.2 <8.4",
"example/module-core": "^1.2"
}Composer will select a compatible Example_Core release. The required dependency version must already be published in a configured repository.
3.5 Validate the Package
composer validate --no-check-publishResolve any validation errors before releasing.
3.6 Commit and Push the Changes
git add .
git commit -m "Prepare Example_Core version 1.0.1"
git push origin mainThis updates the main branch but does not yet create or publish a new Composer version.
3.7 Create the New Version Tag
git tag -a 1.0.1 -m "Example_Core version 1.0.1"
git push origin 1.0.1Verify the published Git tag:
git ls-remote --tags origin3.8 Publish the New Version to Composer
Enter the publisher credentials if they are not already available in the current Terminal session.
read "GITLAB_USER?GitLab deploy token username: "
read -s "GITLAB_TOKEN?GitLab deploy token: "
echoPublish version 1.0.1:
curl --request POST \
--user "$GITLAB_USER:$GITLAB_TOKEN" \
--data-urlencode "tag=1.0.1" \
--write-out "\nHTTP Status: %{http_code}\n" \
"https://git.example.com/api/v4/projects/123/packages/composer"Expected response:
{"message":"201 Created"}
HTTP Status: 201The new release is now available through the private Composer Package Registry.
3.9 Update the Package on Customer Websites
Customers can update an installed package to a newer compatible version using:
composer update example/module-core --with-dependenciesTo explicitly change the required version:
composer require "example/module-core:^1.1"If dependency constraints require related packages to change, use Composer's --with-all-dependencies option where appropriate.
After updating the Magento module, run the relevant Magento deployment commands.
php bin/magento setup:upgrade
php bin/magento cache:flushDepending on deployment mode and module changes, dependency injection compilation and static content deployment may also be necessary.
3.10 Release Checklist
- Update and test the Magento module.
- Review supported PHP and Magento versions.
- Update Composer dependencies if necessary.
- Validate composer.json.
- Commit and push changes to GitLab.
- Create a new release tag.
- Push the tag to GitLab.
- Publish the tag through the Composer API.
- Verify the package in GitLab's Package Registry.
- Test installation or upgrade on staging.
- Release the version to customers.
3.11 Future Improvement: Automatic Publishing
The current workflow publishes Composer packages manually through the GitLab API.
GitLab CI/CD can later automate package publishing whenever a new release tag is pushed.
The CI/CD pipeline should use a securely stored credential with the minimum required publishing permissions.
Conclusion
This process provides a private Composer package distribution workflow using a self-hosted GitLab server.
The example package example/module-core is published as version 1.0.0 and can be installed using Composer.
The same approach can be reused for other proprietary Magento modules, including packages with dependencies on shared core modules.
Customer-specific read-only deploy tokens allow package installation without exposing publisher credentials. More granular customer licensing can be implemented later through a dedicated Composer distribution service.