Skip to content

Ship the default config in each core package and add config:publish #649

Open

Description

@armanist

Summary

Move the default configuration of the app-wide packages (cache, mailer, session, lang, logging, view, view_cache, fs, rate_limit, captcha, database, auth, cors) from the starter project into the framework's packages. Each package ships its defaults, Config merges them under the application's file, and a new php qt config:publish command copies a default into shared/config/ for editing.

Why

  • The framework loads 15 config files in 16 places, always as config()->import(new Setup('config', '<name>')), and throws a ConfigException when one is missing. So it depends on files that only the starter project ships.
  • Every release needs hand edits in the application. The 3.1.0 starter project had to add the resend mailer entry, logging.message.limit and mailer.transport_log_limit, change the shape of lang.php, and remove hooks.php. An existing application never receives them.
  • The framework already has half of the idea: UploadConfigProvider and LoggerConfig keep defaults in code, and module:generate copies module config from templates. The app-wide packages have neither a default nor a merge, and Config::import throws when a name is imported twice.
  • Laravel (mergeConfigFrom and vendor:publish) and Symfony (Flex recipes) both keep the defaults next to the code that reads them.

Scope

  1. Defaults per package, at src/<Package>/config/<name>.php, with the same keys and env() reads as the starter project's file today.
  2. Config resolves a name from three layers: the package default (lowest), then shared/config/<name>.php, then the module's file, where the later layer wins. A missing application file is no longer fatal.
  3. php qt config:publish <name> (and --all) copies a default into shared/config/, and does not overwrite an existing file without a flag.
  4. The starter project keeps its config files at first, so no application breaks. Trimming them is a later, separate change.

Designed for extracted packages

The packages are to be extracted into separate Composer packages later, and their config has to install the same way, or almost:

  • a package's defaults live inside its own folder and reference nothing outside it;
  • defaults are found through a registry (package name to config path) that each package registers, and Config does not hard-code a path;
  • config:publish works by package name, so an extracted package registers itself and the same command publishes it;
  • a Composer plugin that copies the config on install can be added later on top of this. It is not a prerequisite.

To decide

  • how lists and nested arrays merge (replace or merge by key)
  • whether an application still needs its own file for the required packages
  • whether the starter project keeps full copies or only the values that differ from the defaults

Related

Out of scope

  • Moving or splitting any package into its own repository.
  • A Composer plugin.

Acceptance criteria

  • an application with no shared/config/cache.php boots and uses the cache defaults
  • a value in shared/config/<name>.php wins over the default, and a key it omits falls back to the default
  • an application that keeps its current config files behaves exactly as before
  • php qt config:publish <name> writes the default file and refuses to overwrite an existing one without a flag
  • a package registers its defaults in one place, and removing that registration is the only change needed to extract the package
  • tests cover the merge order, the missing application file and the publish command

Activity

  1. added this to the 3.2.0 milestone on Nov 3, 2026
  2. added
    enhancementNew feature or request
    configConfiguration package and loading
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    configConfiguration package and loadingenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions