A Technical Rundown of How Project Config Works

15 April 2019

As of Craft 3.1.0, Pro­ject Con­fig” is a thing. Here’s a tech­nic­al run­down of how it works.

Project config database

Over­view #

  • Pro­ject con­fig is always on.
  • Pro­ject con­fig is respons­ible for the site schema.
  • Pro­ject con­fig is stored in the con­fig column of the Info table in the data­base as a seri­al­ized JSON encoded (as of 3.1.33) array.
  • Pro­ject con­fig is backed up auto­mat­ic­ally and stored in .yaml files in storage/config-backups.
  • Pro­ject con­fig data should only be edit­able by admins.

The Pro­ject Con­fig File #

  • Enabling useProjectConfigFile tells Craft to store pro­ject con­fig in a config/project.yaml file and use that ver­sion as the single source of truth.
  • Craft mon­it­ors the project.yaml file for changes and if it detects any then syncs them to pro­ject con­fig in the database.
  • As a best prac­tice, site schema changes should only be made in the envir­on­ment in which the project.yaml file is ver­sion con­trolled and deployed from.
  • The value stored in the con­fig column of the Info table is what is loaded on each reg­u­lar request (for optim­isa­tion purposes).

Caveats #

  • If Craft detects that project.yaml has changed but that the ver­sions of Craft and plu­gins in the file are incom­pat­ible with what’s actu­ally installed then access to the con­trol pan­el will be denied. Run­ning composer install should resolve any discrepancies.
  • Use envir­on­ment vari­ables to store sens­it­ive inform­a­tion in set­tings so as to pre­vent them being stored in plain­text in pro­ject config.

Plu­gins #

  • Plu­gins that manip­u­late the site schema should do so using ser­vice APIs or the Pro­ject­Con­fig ser­vice instead of dir­ectly in the database.
  • Plu­gins that store ref­er­ences to site schema com­pon­ents in pro­ject con­fig should store the UIDs (uni­ver­sally unique iden­ti­fi­ers) instead of the IDs of those com­pon­ents, as IDs may be dif­fer­ent across envir­on­ments but UIDs will not.

Plu­gin Migra­tions #

  • Plu­gin migra­tions that update the site schema (includ­ing their own set­tings) should do so using the Plu­gins ser­vice or their own ser­vices instead of dir­ectly in the data­base. These updates will be car­ried over to oth­er envir­on­ments when useProjectConfigFile is set to true.

  • Plu­gin migra­tions are applied before apply­ing all the oth­er project.yaml changes, so if you update pro­ject con­fig file from a plu­gin migra­tion, the end res­ult is that Craft thinks that the project.yaml file is synced already and the oth­er changes nev­er get applied. It may also res­ult in an excep­tion being thrown if allowAdminChanges is set to false in the envir­on­ment in which the migra­tion is being run and changes to pro­ject con­fig are not allowed. A schema ver­sion check should to be made against the project.yaml file (not the data­base) to pre­vent this situation. 

    // Don't make the same config changes twice
    $schemaVersion = Craft::$app->projectConfig->get('plugins.myPluginHandle.schemaVersion', true);
    
    if (version_compare($schemaVersion, '1.1.0', '<')) {
      // Make the config changes here...
    }
  • By set­ting the muteEvents flag on the ProjectConfig ser­vice to true, you can pre­vent changes in project.yaml from trig­ger­ing events. This is use­ful if you want to modi­fy some­thing com­plex in plu­gin set­tings, for example. The best way to do it is to set the flag to true, make your changes to both pro­ject con­fig and then data­base and then be sure to set the flag back to false. Not doing so will cause any site schema changes in project.yaml to be ignored and poten­tially res­ult­ing in things being out of sync.

Site Schema #

  • Asset volumes and image transforms
  • Cat­egory groups 
  • Email set­tings
  • Fields and field groups
  • Glob­al set settings
  • Mat­rix block types
  • Plu­gin settings
  • Routes defined in Set­tings → Routes
  • Sec­tions and entry types
  • Sites and site groups
  • Sys­tem settings
  • Tag groups
  • User groups and settings