Creating Laravel Packages. For Dummies.

A complete tutorial to Laravel Packages, from version 5.1 to 8+

Cristian Tăbăcitu
4 min readJun 26, 2015

Unfortunately, Laravel's documentation on how to create a package is an introduction, at best. It’s important to read it - to understand the concept - but it’s not a step-by-step guide to creating your first package. This is.

Last updated in March 2020 — used it to create a tutorial for Backpack for Laravel add-ons.

Step 1. Install Laravel

For this, check out Laravel’s docs. As an alternative, use an existing Laravel application. Don’t forget you need to:

composer install


chmod -R o+w storage
chmod -R o+w vendor

Step 2. Create your package

We’re going to use this CLI tool to generate a new package. Follow the instructions in the Installation chapter there to create a new package. If you already have it, run:

php artisan packager:new myvendor mypackage

If unsure, use your github username for myvendor. For example, Jeffrey Way uses “way”.

This will create a /packages/ folder in your root directory, where your package will be stored so you can build it. It will also pull a very basic package template, created by thephpleague. Everything you have right now is in packages/myvendor/mypackage.

Now let’s customise it and add some boilerplate code, everything that most Laravel Packages will need.

  1. Replace everything you need in composer.json,,,, Make it yours.
  2. In /src/ you’ll find your service provider. That’s where your package’s logic is, but it’s empty. Use this Service Provider template and replace “League” with your “myvendor” and “Skeleton” with your “mypackage”.
  3. Your package will probably need some Controllers, routes and config files, so let’s create some empty files for that.
cd /src/
mkdir Http
mkdir Http/Controllers
echo "<?php " >Http/routes.php
mkdir config
echo "<?php " >config/config.php
mkdir resources
mkdir resources/views/

You use the routes, config and controller files just like you use the ones in your application. Nothing changes there. But remember that the controller should have the package’s namespace:

namespace MyVendor\MyPackage\Http\Controllers;

4. Check that your service provider is in your app’s /config/app.php

If not, add it:


5. Check that you autoload your package in composer.json:

"autoload" : {
"psr-4": {
“Domain\\PackageName\\”: “packages/Domain/PackageName/src”

6. Let’s recreate the autoload

cd ../../../..
composer dump-autoload

7. If you have a config file to publish, do:

php artisan vendor:publish

8. Test it. If you are having problems, start by doing a dd(‘testing) in your service provider’s boot() function.

If your package is working fine, you should make it available for others to use.

Step 3. Put it on GitHub

cd packages/domain/packagename/
git init
git add .
git commit -m “first commit”

Create a new GitHub repository.

git remote add origin
git push -u origin master
git tag -a 1.0.0 -m ‘First version’
git push --tags

The tags are the way you will version your package, so it’s important you do it.

Step 4. Put it on Packagist

On, submit a new package. Enter you package’s GitHub URL and click Check. If any errors occur, follow the onscreen instructions.

When you’re done, you’re taken to your package’s packagist page, where you’ll probably get a notice like this:

This package is not auto-updated. Please set up the GitHub Service Hook for Packagist so that it gets updated whenever you push!

Let’s take care of that. Click that link, get your API token and go to your package’s GitHub page, in Settings / Webhooks & Services / Add a new service. Search for Packagist. Enter your username and the token and hit Submit. Your error in Packagist should dissapear in 5–10 minutes.

Congrats, you have a working package online, you can now require it in composer.

Step 5. Keep working on it from your vendor folder

If the application where you’ve developed the package had this sole purpose — to help you develop the package, you’re done.

But if you’ve developed the package in a bigger project, where you are now requiring it, you have a problem — your composer.json has both:

"require": {
"domain/package-name": "^1.0"


"autoload" : {
"psr-4": {
“Domain\\PackageName\\”: “packages/Domain/PackageName/src”

Plus, the same files are in /packages/myvendor/mypackage AND in /vendor/myvendor/mypackage.

Let’s solve this:

1. Delete the /packages/myvendor/mypackage folder.

2. Delete the psr-4 mention in your root composer.json.

Done. Now you only have it in /vendor/ and that’s where your application is using it from. But now you can’t push updates, because /vendor/myvendor/mypackage/ doesn’t have your git repository, only the files. Let’s fix that.

3. Delete /vendor/myvendor/mypackage:

cd ../../..
rm -rf vendor/myvendor/mypackage

4. Run composer with the — prefer-source flag, so it clones the repo:

composer install --prefer-source

That’s it, you can now cd to /vendor/myvendor/mypackage, make your changes and push them, just like any other git repository.



Cristian Tăbăcitu

Creator of Backpack for Laravel & ScheduleThatEmail. I build web products - for work and for fun.