DEV Community

Cover image for Building a Plugin-Based Django Architecture with Horilla’s `AppLauncher`
Horilla
Horilla

Posted on

Building a Plugin-Based Django Architecture with Horilla’s `AppLauncher`

Modern Django applications often start small.

But as the platform grows, developers begin facing the same problems:

  • Repeated URL registrations
  • Manual signal imports
  • Scattered Celery configurations
  • Frontend asset duplication
  • Tight coupling between apps and the core project

At Horilla Open Source HRMS & CRM, we wanted a more scalable approach for building modular enterprise applications in Django.

Instead of treating Django apps as isolated modules, we wanted apps to behave like plugins that could automatically integrate themselves into the platform.

That led to the creation of:

AppLauncher — Horilla’s Plugin Architecture Layer for Django

AppLauncher is a reusable extension of Django’s AppConfig that enables:

  • Automatic URL registration
  • Plugin-style app loading
  • Auto-discovery of signals and menus
  • Dynamic JavaScript asset registration
  • Celery schedule integration
  • Modular HRMS and CRM architecture
  • Scalable enterprise Django development

This architecture helps Horilla function not only as an HRMS platform, but also as an extensible Django ecosystem.


Why Traditional Django App Wiring Becomes Difficult at Scale

In a standard Django project, every new app usually requires manual integration.

For example:

Manual URL Registration

urlpatterns = [
    path("crm/accounts/", include("horilla_crm.accounts.urls")),
]
Enter fullscreen mode Exit fullscreen mode

Manual Signal Imports

class AccountsConfig(AppConfig):
    def ready(self):
        import horilla_crm.accounts.signals
Enter fullscreen mode Exit fullscreen mode

Manual Celery Schedule Registration

CELERY_BEAT_SCHEDULE.update(...)
Enter fullscreen mode Exit fullscreen mode

Manual JavaScript Injection

<script src="/static/accounts/app.js"></script>
Enter fullscreen mode Exit fullscreen mode

This approach works for small projects.

But in large-scale systems like:

  • HRMS platforms,
  • CRM software,
  • ERP systems,
  • SaaS applications,
  • multi-module Django platforms,

manual wiring creates:

  • duplicated setup,
  • maintenance overhead,
  • tight coupling,
  • onboarding complexity,
  • scalability problems.

The Goal: Build a Plugin-Based Django Platform

At Horilla, we wanted new apps to behave like installable plugins.

Meaning:

  • apps should self-register,
  • modules should auto-discover themselves,
  • frontend assets should load dynamically,
  • and the core platform should remain untouched.

Instead of this workflow:

“Add your app manually to multiple core files.”

We wanted:

“Install the app and it automatically integrates with the platform.”

This is the foundation of scalable plugin architecture in Django.


Introducing AppLauncher

Horilla introduces a reusable base class:

class AppLauncher(AppConfig):
Enter fullscreen mode Exit fullscreen mode

Every modular app extends this class instead of directly inheriting from Django’s AppConfig.

Example:

class AccountsConfig(AppLauncher):

    name = "horilla_crm.accounts"

    url_prefix = "crm/accounts/"
    url_module = "horilla_crm.accounts.urls"
    url_namespace = "accounts"

    js_files = "accounts/assets/js/accounts.js"

    auto_import_modules = [
        "registration",
        "signals",
        "menu",
        "dashboard",
    ]
Enter fullscreen mode Exit fullscreen mode

That is enough to integrate the app into the Horilla platform.

No:

  • root URL modifications,
  • manual imports,
  • repetitive startup logic,
  • duplicated initialization code.

How Horilla’s AppLauncher Works Internally

When Django starts, it loads installed applications and calls:

ready()
Enter fullscreen mode Exit fullscreen mode

Horilla extends this lifecycle hook:

def ready(self):
    self._register_urls()
    self._register_js()
    self._auto_import_modules()
    self._register_celery_schedule()
Enter fullscreen mode Exit fullscreen mode

This creates automatic platform-level integration for every app.


1. Automatic URL Registration in Django

Apps define:

url_prefix = "crm/accounts/"
url_module = "horilla_crm.accounts.urls"
Enter fullscreen mode Exit fullscreen mode

Horilla dynamically injects URLs into the root URL configuration:

urlpatterns.append(
    path(
        self.url_prefix,
        include(self.url_module),
    )
)
Enter fullscreen mode Exit fullscreen mode

Benefits

  • No manual urls.py edits
  • Reduced coupling
  • Easier app installation
  • Better modularity
  • Cleaner large-scale architecture

This is especially useful in enterprise Django platforms with many independent modules.


2. Automatic Module Discovery

Apps declare modules for automatic loading:

auto_import_modules = [
    "signals",
    "menu",
    "dashboard",
]
Enter fullscreen mode Exit fullscreen mode

Horilla dynamically imports them:

importlib.import_module(f"{self.name}.{module}")
Enter fullscreen mode Exit fullscreen mode

Why This Matters

This enables:

  • automatic signal registration,
  • dynamic menu loading,
  • dashboard widget discovery,
  • plugin lifecycle initialization.

If an app contains:

  • signals.py
  • menu.py
  • dashboard.py

Horilla automatically activates them.

This follows the powerful software design principle:

Convention Over Configuration

Instead of manually configuring everything, the framework follows predictable conventions.

This approach is used in:

  • Ruby on Rails
  • Laravel
  • VSCode extensions
  • browser plugin systems

3. Dynamic JavaScript Asset Registration

Apps can contribute frontend assets declaratively:

js_files = [
    "accounts/assets/js/accounts.js"
]
Enter fullscreen mode Exit fullscreen mode

Internally:

register_js(self.js_files)
Enter fullscreen mode Exit fullscreen mode

This allows Django apps to inject frontend behavior without modifying shared templates.

Advantages

  • Cleaner frontend architecture
  • Better HTMX/JavaScript modularity
  • Reduced template duplication
  • Easier feature isolation
  • Dynamic UI extensibility

4. Automatic Celery Beat Schedule Integration

Large enterprise systems often require background jobs.

With Horilla, apps can ship their own Celery schedules:

celery_schedule_module = "celery_schedules"
Enter fullscreen mode Exit fullscreen mode

Horilla automatically merges:

HORILLA_BEAT_SCHEDULE
Enter fullscreen mode Exit fullscreen mode

into:

settings.CELERY_BEAT_SCHEDULE
Enter fullscreen mode Exit fullscreen mode

Benefits

  • Decentralized task management
  • Better app ownership
  • Cleaner background job architecture
  • Easier scaling of scheduled services

Why AppLauncher Changes Django Architecture

The biggest architectural shift is this:

Traditional Django Architecture

Core project controls apps
Enter fullscreen mode Exit fullscreen mode

Horilla Plugin Architecture

Apps extend the platform themselves
Enter fullscreen mode Exit fullscreen mode

This transforms Django from:

  • a collection of apps

into:

  • a scalable modular platform.

Building Scalable HRMS & CRM Systems with Django

Horilla uses this architecture to build:

  • HRMS modules,
  • CRM modules,
  • attendance systems,
  • employee management,
  • recruitment systems,
  • payroll integrations,
  • enterprise workflows.

Because apps are plugin-oriented, new business modules can integrate into the platform with minimal core modifications.

This dramatically improves:

  • maintainability,
  • developer experience,
  • scalability,
  • onboarding,
  • long-term architecture health.

Plugin Architecture in Django: Key Benefits

Using AppLauncher, a new app can automatically provide:

  • URLs
  • signals
  • menus
  • dashboards
  • APIs
  • Celery jobs
  • frontend assets
  • startup hooks

without modifying the core platform.

This creates:

  • self-contained Django apps,
  • reusable enterprise modules,
  • cleaner platform architecture,
  • extensible SaaS foundations.

Framework Thinking vs Traditional App Thinking

Many Django projects focus only on:

  • models,
  • views,
  • templates.

But large-scale platforms require:

  • extension points,
  • lifecycle hooks,
  • auto-discovery systems,
  • registries,
  • plugin loaders,
  • modular conventions.

AppLauncher became one of the core abstractions that helped Horilla evolve into a modern modular HRMS platform built with Django.


Final Thoughts

Django already provides excellent architectural foundations through AppConfig.

But small abstractions can create massive long-term improvements.

By extending Django with plugin-style architecture patterns like AppLauncher, developers can build:

  • scalable enterprise platforms,
  • modular SaaS systems,
  • reusable HRMS applications,
  • extensible CRM ecosystems,
  • maintainable large-scale Django projects.

For Horilla, AppLauncher became one of the foundational building blocks enabling platform-level scalability.


About Horilla

Horilla Open Source is a modular Django-based HRMS & CRM and enterprise management platform focused on:

  • scalability,
  • extensibility,
  • modern UI architecture,
  • HTMX integration,
  • plugin-based modularity,
  • enterprise workflow management.

Explore Horilla

If you are building large Django applications, modular HRMS systems, CRM platforms, or enterprise SaaS products, plugin-style architecture can significantly improve maintainability and scalability.

Top comments (0)