neoground / charm
Charm Framework
Fund package maintenance!
Requires
- php: >=8.4
- ext-fileinfo: *
- ext-json: *
- ext-openssl: *
- claviska/simpleimage: ^4.4
- dragonmantank/cron-expression: ^3.6
- filp/whoops: ^2.18
- guzzlehttp/guzzle: ^8.0
- illuminate/database: ^13.25
- kint-php/kint: ^6.1
- league/flysystem: ^3.35
- league/flysystem-sftp-v3: ^3.33
- monolog/monolog: ^3.10
- nesbot/carbon: ^3.13
- opis/closure: ^4.5
- php-debugbar/php-debugbar: ^3.8
- phpmailer/phpmailer: ^7.1
- phpunit/phpunit: ^13.3
- phroute/phroute: ^2.2
- predis/predis: ^3.2
- respect/validation: ^2.5
- symfony/console: ^8.1
- symfony/yaml: ^8.1
- twig/twig: ^3.28
Suggests
- ext-pcntl: Required when you want to use the built-in cron daemon
- ext-redis: For native redis support instead of using predis
- kint-php/kint-twig: Provides d() and s() functions in twig templates
README
A fast, modular PHP framework for ambitious web applications, APIs and SaaS.
Developed and used in production by Neoground.
Charm is a full-stack PHP framework built around a straightforward idea: provide the infrastructure a serious application repeatedly needs, while keeping the execution model compact, predictable and easy to reason about.
It combines a conventional MVC application structure with attribute-based routing, Twig, Eloquent, YAML configuration, authentication, caching, queues, scheduling, events, storage, HTTP tooling and a modular application system. Applications can stay small, grow into substantial monoliths, or be divided into explicit modules without changing the underlying programming model.
Charm is deliberately compact, not minimal. It is intended for developers who want an integrated framework without making framework machinery the dominant complexity of the application.
What Charm is built for
Charm is a practical foundation for:
- SaaS and business applications
- APIs and application backends
- server-rendered websites with Twig
- hybrid applications with modern JavaScript frontends
- internal tools and operational platforms
- modular monoliths and reusable application modules
Neoground uses Charm as the foundation for its own web platforms, products and client systems. The framework therefore prioritizes maintainability, operational usefulness and predictable application architecture over abstraction for its own sake.
Design principles
Direct by default
Charm keeps common application operations close to the code that uses them. Routes can live directly on controller
methods, table definitions can live with models, configuration is accessed through a consistent API, and initialized
framework modules are available through C::.
use Charm\Vivid\C; $term = C::Request()->get('term'); $hostname = C::Config()->get('connections:database.hostname'); $queue = C::Queue();
The same module model extends to custom modules. Charm does not require deep service graphs or runtime controller-parameter resolution for ordinary application code.
Full-stack without unnecessary ceremony
The framework includes the recurring systems needed by production applications rather than leaving every project to assemble them independently. That includes routing, requests and responses, views, database access, auth, queues, scheduling, events, cache, storage, mail, validation, logging and development tooling.
The goal is not to hide PHP behind a large abstraction layer. The goal is to remove repetitive infrastructure while keeping application flow visible.
Modular when the application needs it
A Charm application can remain one coherent codebase or be split into modules with their own namespaces, configuration
and application structure. Modules are registered through modules.yaml and participate in the same initialization and
runtime model as the framework itself.
This makes it possible to structure a larger application by domain without prematurely turning it into a distributed system.
Optimized initialization
Charm initializes its modules into a shared application context and uses AppStorage for frequently accessed
lightweight runtime data such as configuration and routing metadata.
For production environments, stable initialization data can be generated into an AppStorage cache. This avoids repeating work that does not need to be rediscovered on every request and keeps framework bootstrapping lean.
Core capabilities
| Area | Included |
|---|---|
| Application structure | MVC foundation, controllers and models with subdirectory support, modular applications |
| Routing | Attribute-based routes, named routes, groups, filters and module routes |
| Views | Twig templates, layouts, includes, framework helpers and custom responses |
| Database | Eloquent ORM, multiple SQL database engines, model-based table definitions and migrations |
| Configuration | YAML configuration, environment-specific overrides, translations and cached initialization |
| Modules | Built-in and custom modules exposed through the same C::Module() interface |
| Authentication | Web authentication, guards, sessions and token-based API authentication |
| Background work | Queue system and scheduled jobs |
| Application services | Events, caching, Redis, HTTP client, mail, validation, logging and file storage |
| Developer tooling | Bob CLI, debug mode, exception handling, Debug Bar and Kint integration |
Charm uses established libraries where they solve a problem well—including Twig, Eloquent, Symfony components, Flysystem, Guzzle and Monolog—while providing a coherent Charm application layer around them.
A small Charm application
A controller route can be defined directly where its behavior lives:
namespace App\Controllers; use Charm\Vivid\C; use Charm\Vivid\Controller; use Charm\Vivid\Kernel\Output\View; use Charm\Vivid\Router\Attributes\Route; class WelcomeController extends Controller { #[Route('GET', '/hello', 'welcome.hello')] public function hello() { $name = C::Request()->get('name', 'World'); return View::make('welcome')->with([ 'name' => $name, ]); } }
The corresponding Twig view can stay equally direct:
{% extends "_base/main.twig" %}
{% block content %}
<h1>Hello {{ name }}</h1>
<p>{{ c('Config').get('user:site_name') }}</p>
{% endblock %}
Models are based on Eloquent and can keep their basic table definition close to the model when that is the clearest representation of the application:
namespace App\Models; use Charm\Vivid\Model; use Illuminate\Database\Schema\Blueprint; class Project extends Model { protected $table = 'projects'; protected $fillable = [ 'name', 'status', ]; public static function getTableStructure(): \Closure { return function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('status')->default('active'); $table->timestamps(); }; } }
Traditional migrations remain available when a project benefits from a separate migration history.
Requirements
- PHP 8.4 or later
- Composer
- required PHP extensions:
- JSON
- Fileinfo
- OpenSSL
- optional, depending on the application:
- MariaDB, MySQL, SQLite, PostgreSQL or SQL Server
- Redis
ext-pcntlfor the built-in cron daemon
Charm is developed for current PHP versions and makes use of modern PHP language features.
Getting started
The recommended way to create a Charm application is with Bob, the Charm command-line toolkit, and the official Charm Wireframe project template.
1. Install Bob
curl -fSsL -o bob https://raw.githubusercontent.com/neoground/charm-toolkit/main/bob \
&& chmod +x bob
sudo mv bob /usr/local/bin/bob
See the Charm Toolkit repository for Bob documentation.
2. Create a project
bob new AcmePortal
Bob creates a new application from charm-wireframe and guides you through the initial setup.
3. Configure the application
Global configuration lives in:
app/Config/
Environment-specific overrides live below:
app/Config/Environments/<Environment>/
The active environment is selected through app/app.env.
Typical configuration files include:
main.yaml
connections.yaml
modules.yaml
4. Run the development server
bob serve
The Wireframe also includes example configuration for Nginx and Apache deployments.
Application structure
A conventional Charm project keeps the important parts easy to locate:
app/
├── Config/
├── Controllers/
├── Models/
├── Views/
└── ...
As the project grows, controllers and models can be grouped into subdirectories or application domains can be promoted into dedicated Charm modules. The framework does not require a change of architectural style simply because the codebase becomes larger.
Modules and C::
Framework services and loaded application modules share one access pattern:
C::Config(); C::Request(); C::Cache(); C::Queue(); C::Storage();
A custom module follows the same model:
C::Billing()->createInvoice($order);
This gives applications a small and consistent surface area while keeping modules independently structured and reusable.
Charm:: is available as the long-form alias of C::.
Production use
Charm is maintained alongside the systems Neoground builds and operates, and its architecture is shaped by production requirements.
Production deployments can generate the AppStorage cache so stable initialization data is loaded directly rather than rebuilt on each request:
php bob.php appstorage:generate
The framework also provides integrated logging, caching, queues, scheduled tasks, storage abstraction and debug tooling for the operational lifecycle around an application.
Charm 4
Charm 4 is a substantial architectural revision and introduces breaking changes from the 3.x line. Its purpose is to establish a cleaner long-term foundation for Neoground's applications and for external projects building on Charm.
Charm is already used in production, but projects tracking the development line should expect APIs to continue evolving until the 4.0 stable release.
Documentation
The documentation is being revised alongside Charm 4. Some sections may still describe earlier framework versions or terminology.
Contributing
Issues, bug reports and focused pull requests are welcome through GitHub.
If you are planning a larger contribution or architectural change, opening an issue first helps keep the work aligned with the framework's direction.
License
Charm is open source software released under the MIT License.
About Neoground
Charm is developed and maintained by Neoground GmbH, a German technology company working across strategic technology advisory, software systems and digital infrastructure.
We build Charm because we use it: as a durable, understandable foundation for software that has to work beyond the prototype stage.