Craft's project.yaml, from someone who's been burned by Drupal config sync
I've spent years doing the Drupal config dance: drush cex, commit the YAML, drush cim on deploy, and the occasional cold sweat when an import threatens to delete something because "code owns config, full stop." So picking up a Craft CMS backend, the first thing I went looking for was Craft's answer to config management. It has one — project config — and it solves the same problem with a noticeably gentler philosophy. Gentler is mostly good. It's also a trap if you're not disciplined.
What project config is
Craft stores your site's structure — fields, sections, entry types, sites, GraphQL schemas, user groups, email settings — as version-controlled YAML under config/project/ (split across multiple files, not one monolith). You change the schema in one environment, commit the YAML, and apply it elsewhere. Same goal as Drupal config sync: keep environments' structure in git and move it like code.
The one philosophical difference that matters
Here's the distinction a Drupal dev feels immediately. In Drupal, exported config is the source of truth and the active config bows to it — an import can and will remove things not in the sync directory. In Craft, the database stays the runtime source of truth; the YAML is the canonical definition of settings, and on apply, YAML drives the database. Crucially, you can regenerate the YAML from the database with project-config/rebuild when they drift. Drupal has no real equivalent to "just rebuild my config export from what's actually running."
The command set will feel familiar but softer:
php craft project-config/apply— diff YAML against loaded config and apply the delta (yourcim).php craft up— the deploy workhorse: runs pending migrations and applies project config in one shot.php craft project-config/rebuild— regenerate YAML from the DB when things drift (no Drupal analogue).php craft project-config/touchthenapply— the merge-conflict recovery ritual, which exists precisely because YAML merge conflicts happen here too.
The trap: softness invites drift
Because the DB is authoritative at runtime and YAML can be rebuilt from it, Craft is far less likely to hand you Drupal's nastiest failure mode — the import that nukes a field because it wasn't in code. That's a genuine relief. But the same forgiveness means environments will happily drift apart if you let people change structure in production. The fix is a setting every serious Craft project must set, and the docs are blunt about it: allowAdminChanges = false on every non-dev environment. That makes Settings read-only even for admins, locks the edition and plugin versions, and turns project config and the Plugin Store read-only — so prod can't wander off and get clobbered on the next deploy.
Drupal's config system assumes code is law and enforces it rigidly. Craft's assumes you'll be sensible and gives you the rope to be otherwise. Neither has solved YAML merge conflicts, and both let you down exactly once before you learn to respect them.
The honest verdict
After the Drupal comparison, my take: Craft's project config is friendlier day-to-day and easier to reason about, especially for a small team. The "rebuild from the database" escape hatch alone has saved me the kind of afternoon I've lost to Drupal config-split gymnastics just to keep a dev-only module out of prod. Drupal's model is more ceremonious and more rigid — but that rigidity buys predictability and governance that pays off on big, strict, many-developer builds. If you're coming from Drupal, the mental shift isn't the commands (those map over cleanly); it's internalizing that in Craft the database is still in charge, and that allowAdminChanges = false is the seatbelt that turns "gentle" into "safe."