The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


KelpX::Symbiosis - Fertile ground for building Plack apps


        # in configuration file
        modules => [qw/SomeSymbioticModule/],
        modules_init => {
                SomeSymbioticModule => {
                        mount => '/elsewhere', # a path to mount SomeSymbioticModule

        # in main application file
        package KelpApp;
        use Kelp::Base 'KelpX::Symbiosis';

        sub build {
                my $symbiosis = $kelp->symbiosis;
                $symbiosis->mount('/other-path' => $kelp->module_method);
                $symbiosis->mount('/other-path' => 'module_name'); # alternative - finds a module by name

        # in psgi script
        my $app = KelpApp->new();


KelpX::Symbiosis is a new, mostly backward-compatible approach to Symbiosis. Instead of loading it as a Kelp module Kelp::Module::Symbiosis, you base your main class on KelpX::Symbiosis. It will then use your Kelp application router to reach all the Plack apps instead of Plack::App::URLMap. Thanks to this you can have more unified environment when it comes to stuff like error pages, bridges and hooks.


Here are the differences when compared to Kelp::Module::Symbiosis. See its documentation for full reference, but keep these points below in mind.


All system routing goes through the Kelp router

You can mix apps and Kelp actions, set bridges and build urls to all application components.

Defined routes for apps do not match with suffixes by default

If you defined a static file app to be under /static and someone made a request to /static/file.txt, it will not be matched under KelpX::Symbiosis. You should probably define the routes for symbionts as /static/>rest, which will match both /static and /static/path/file.txt. Use the same techniques for defining paths as you would in Kelp, for example you can mount an app under [POST => qr/save$/].

If you wish to properly preserve the rest of the path to the app (which you should), it's a good idea to end your route with a named placeholder, like />rest. If you don't name it and the app contains other named placeholders then path will not be preserved correctly (as it then won't be included in route handler params).

It's also not correct to have a pattern like /any:thing, because Plack requires path to start with a slash. In this case of request /anyone, the actual request would be to reach out for /any/one, where the script name would end up being /any and the path would become /one. (it would still match /anyone, but these are the values which will be set up for the mounted app).

run method runs the whole ecosystem

run_all is provided for backcompat, but is just an alias for run.


Symbiosis configuration values are at top-level of configuration

All configuration from "CONFIGURATION" in Kelp::Module::Symbiosis is taken from top-level hash instead of modules_init.Symbiosis hash.

mount cannot be configured for the main Kelp app

Kelp will always be mounted at the very root. The module will throw an exception if you try to configure a different top-level mount.

Does not allow to assign specific middleware for the Kelp app

Middleware from the top-level middleware will be wrapping the app, but all other apps will have to go through it. It's impossible to have middleware just for the Kelp app.


KelpX::Symbiosis::Test is no longer required

KelpX::Symbiosis::Test was used as a wrapper for testing Symbiosis-based apps. Since now Symbiosis does not wrap Kelp in anything there is no need to use it in favor of Kelp::Test unless you use Kelp::Module::Symbiosis. It will continue to work with any Symbiosis variant though.



This module will try to detect if you're using Kelp::Less on import. If you do, it will replace the Less app instance with Symbiosis. Make sure you import Kelp::Less before you import KelpX::Symbiosis.

        use Kelp::Less;
        use KelpX::Symbiosis;

        module 'Symbiont', mount => '/app1';



Wrapping some apps in the same middleware as your main app may be redundant at times. For example, wrapping a static app in session middleware is probably only going to reduce its performance. If it bothers you, you may want to switch to Kelp::Module::Symbiosis.