Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Lumen Laravel Package

orchestra/lumen

Orchestra Lumen brings Orchestra Platform-style service providers, extensions, and resource management to the Lumen micro-framework, helping you bootstrap configuration and structure for fast, lightweight Laravel-based APIs and services.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat the first hour as a feasibility spike, not a setup task. This package is a bridge between two ecosystems that both move, with zero stars and zero dependents — so there is no composer require success story to rely on. Before you write a line of feature code:

composer require orchestra/lumen --dry-run
composer show orchestra/lumen --tree

The --tree output is the important one. It tells you whether you are pulling the full orchestra/foundation admin/extension surface or only the lighter contracts (orchestra/support, orchestra/memory, orchestra/authorization). The first is an order of magnitude harder to keep alive. Pin whatever version resolves and commit the lockfile the same day.

Nothing is auto-discovered and nothing is auto-published. Lumen does not do provider discovery and, unless you have installed lumen-generator, it has no vendor:publish. Two manual steps stand between composer require and a working app.

Copy configs by hand:

cp -r vendor/orchestra/lumen/config/* config/

Register the provider by hand, in bootstrap/app.php:

$app = new Laravel\Lumen\Application(realpath(__DIR__.'/../'));

$app->withFacades();   // Orchestra providers assume a facade root
$app->withEloquent();  // only if the Orchestra surface you use needs models

// Lumen has no config auto-load: each key must be declared explicitly
$app->configure('orchestra');
$app->configure('app');

$app->register(Orchestra\Lumen\Providers\LumenServiceProvider::class);

Where to look first in the source. Read src/Providers/ and config/ before anything else. The provider list is the honest inventory of which Orchestra contracts are actually bridged versus silently absent; the config directory is the list of keys you must declare with $app->configure(). Do not infer capability from the package description — infer it from the provider list.

First use case: probe the container, not the routes. Skip routing and middleware on day one. Register one Orchestra contract, resolve it from a throwaway route, and confirm the boot order is sane:

$router->get('/_probe', function () {
    return [
        'memory' => get_class(app('orchestra.memory')),
        'config' => config('orchestra'),
    ];
});

A live Orchestra object means the bridge boots. A BindingResolutionException means the provider registered before $app->configure() ran, or the facade root was never set. That probe is the fastest way to separate a Composer problem from a boot-order problem, and you will use it repeatedly.

Implementation Patterns

Wrap the bridge in your own adapter and never call it from feature code. This is the single highest-value pattern with a package of this maturity — it makes the bridge swappable when you inevitably migrate to full Laravel:

namespace App\Support;

interface SettingsStore
{
    public function get(string $key, mixed $default = null): mixed;
    public function set(string $key, mixed $value): void;
}

final class OrchestraSettings implements SettingsStore
{
    public function __construct(private \Illuminate\Contracts\Container\Container $app) {}

    public function get(string $key, mixed $default = null): mixed
    {
        return $this->app['orchestra.memory']->make('settings')->get($key, $default);
    }

    public function set(string $key, mixed $value): void
    {
        $this->app['orchestra.memory']->make('settings')->put($key, $value);
    }
}

Bind the interface in a project-owned provider, not in the package. When you move to Laravel, you replace one binding and nothing else moves.

Mirror the register/boot discipline in your own integration provider. In Lumen the config repository is not necessarily bound when register() runs, so anything that reads config() belongs in boot():

public function register(): void
{
    $this->app->singleton(SettingsStore::class, fn ($app) => new OrchestraSettings($app));
}

public function boot(): void
{
    // config() is safe here, not in register()
    if (config('orchestra.enabled')) {
        // ...
    }
}

Register the package provider last in the boot sequence for the same reason.

Use Lumen's router group as the integration surface, and register middleware aliases explicitly. The web and api groups do not exist the way they do in full Laravel — do not assume them:

$app->routeMiddleware([
    'orchestra' => Orchestra\Lumen\Http\Middleware\Authenticate::class,
]);

$app->router->group([
    'namespace'  => 'App\Http\Controllers',
    'middleware' => 'orchestra',
], function ($router) {
    require __DIR__.'/../routes/web.php';
});

If the package's middleware reaches for session or auth guards Lumen has not registered, you will find out on the first request. The fix is to register the missing Lumen bootstrapper or Illuminate\Session\SessionServiceProvider explicitly rather than hoping the bridge covers it.

Contract-test the bridge, one test per Orchestra concern you depend on. These tests are your changelog, because there is no upstream changelog to diff against:

public function test_orchestra_memory_resolves(): void
{
    $this->get('/_probe')->assertOk()
        ->assertJsonPath('config.enabled', config('orchestra.enabled'));
}

Resolve through the real container, not a mock — the thing you are testing is the wiring, not the class.

Keep the Orchestra bootstrap off hot paths. Extension manifests, config aggregation, and admin bootstrapping are startup-heavy and cache-sensitive. On a stateless API edge, register only what the request path needs and leave the admin/extension providers out of that kernel — ideally, run the admin surface as a separate Lumen application with its own bootstrap.

Gotchas and Tips

Composer constraint overlap is the first incident, not an edge case. Lumen pins illuminate/* on its own cadence; Orchestra packages historically carry tight Laravel constraints. Any unrelated composer update can slide an illuminate/* package out from under the bridge. Pin exact versions, commit the lockfile, and add a separate CI job running composer update --dry-run so drift surfaces before someone blames the bridge for an unrelated bump.

register() cannot read config. The most common failure mode looks like a package bug and is actually a boot-order bug: BindingResolutionException on a class that reads config() during registration. Move the read into boot(), or move your $app->configure() calls earlier in bootstrap/app.php.

Do not trust that a driver "worked" — check which one ran. Lumen does not register session, cache, queue, or broadcast the way Laravel does. An Orchestra provider that assumes Laravel defaults may boot fine and fall back to an in-memory driver in production. Assert the actual driver, not just a 200:

Route::get('/_health', fn () => response()->json([
    'cache'   => config('cache.default'),
    'session' => config('session.driver'),
    'queue'   => config('queue.default'),
]));

$app->withFacades() is not optional if any Orchestra code path touches a static facade. "A facade root has not been set" appearing somewhere that works fine in full Laravel is almost always this.

v5.0.3 should be read as a warning, not a patch note. That release fixed construction of Symfony\Component\ErrorHandler\Error\FatalError — the package reaches into Symfony internals. Every Symfony minor bump is a potential break with no upstream owner. Include a deliberate fatal-error smoke test in staging after any Lumen or Symfony upgrade; do not let the error-handler path go unexercised until production finds it for you.

Debugging checklist, in order:

  1. composer why-not orchestra/lumen — confirms resolution failure and which constraint is blocking.
  2. A tiny bootstrap script dumping $app->getLoadedProviders() — confirms the provider is actually registered.
  3. The /_probe route resolving one contract — confirms boot order and facade root.
  4. Diff config() at boot between local and staging — catches environment-only drift.

Extension points are your only real leverage. Whatever the package exposes in its own provider list is what you can override without forking. Prefer subclassing the package provider and re-registering your subclass over editing vendor/. If you must fork, open a PATCHES.md at the repo root recording the fork point — the next engineer needs to know which lines are yours, because there is no upstream to rebase onto.

Name a single owner for this dependency. With zero dependents there is no community patch stream and no hiring pool for Orchestra-on-Lumen; bus factor is whoever read the boot sequence. Write that name down, keep the provider/config checklist in your README as a migration inventory, and treat that person's departure as a scheduled migration rather than a surprise.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route