SuperAPI AI Directory

craftcms-ops

Coding & development

View repository

Updated 10-13 16:39

About this skill

Craft CMS Operations

Versions verified 2026-10-05 against Packagist and the official docs. Craft 5.x is current (5.11); Craft 4 and 3 are past security support; Craft 6 is in alpha. scripts/check-craft-facts.py --live re-checks the plugin majors on a schedule.

The recurring agency shape: Craft 5 (or a 4/3 site awaiting upgrade) on DDEV, with SEOmatic, Blitz, Formie, and CKEditor, a Vite (or legacy Laravel Mix) front end, and modules tested with Codeception and ECS. This file is the procedure and the router; each topic lives in one reference.

Step 1 - Orient before touching anything

Check Where Tells you
Craft + plugin versions composer.json, ddev composer show craftcms/cms Which line of the version matrix applies - Craft 4 and 5 APIs differ
Local environment .ddev/config.yaml PHP/DB versions; run everything as ddev craft, ddev composer, ddev npm
Schema config/project/*.yaml Source of truth for sections, fields, entry types, plugin settings
Config config/general.php, config/<plugin>.php, .env Environment-specific behaviour (devMode, allowAdminChanges, caching)
Front-end build package.json + config/vite.php, or webpack.mix.js craft-vite or Laravel Mix
Templates templates/_layouts, _partials, _partials/entry/<type>.twig Layout inheritance and element partials
PHP modules/, tests/, codeception.yml, ecs.php Where logic and tests live
Page cache config/blitz.php, Blitz utility Whether what you see is cached HTML - check before debugging "my change isn't showing"

Step 2 - Route the task

Task Read
Listing pages, relations, Matrix/nested entries, pagination, multi-site element-queries.md
Printing anything user-influenced, forms that POST, JS data, rich text output twig-security.md
Meta tags, JSON-LD, sitemaps, robots.txt, hreflang seomatic.md
Static caching, "changes don't show", cache warming, dynamic bits on cached pages blitz.md
Building, theming, or debugging forms; spam; form emails not sending formie.md
Rich-text fields, nested entries inside rich text, Redactor conversion ckeditor.md
Craft on DDEV: the craftcms type, ddev craft, Craft's upload_dirs (generic DDEV: ddev-ops) ddev.md
Tests for modules/plugins, fixtures, ECS/PHPStan codeception.md
Front-end assets, Vite dev server, critical CSS craft-vite.md
Moving off Laravel Mix/Webpack, or Vue 2 to Vue 3 frontend-upgrade-ops (the full migration playbook)
Upgrading Craft 3 → 4 → 5, plugin version lines, Craft 6 status upgrades.md
Slow pages, images, queue setup, production config performance.md
Core Web Vitals failing (LCP, INP, CLS), PageSpeed or Search Console flags web-perf-ops (field data first; its references/craft.md maps the Craft levers)
Headless front ends, GraphQL schemas and tokens graphql.md
Modules, plugins, events, migrations, queue jobs plugin-development.md
Modeling a new flexible page type assets/entry-type-field-layout.md

Step 3 - Hold the non-negotiables

  1. Eager-load before you loop. .with([...]) up front; .eagerly() inside shared partials (Craft 5 only). One query per card is the most common Craft perf bug.
  2. Escape by context. Never |raw user-influenced values; |e('js') inside JS strings; {{ csrfInput() }} in every POST form - csrfInput({ async: true }) on cached pages.
  3. Schema only through Project Config. Change it in the CP locally, commit config/project/, run php craft up on deploy. Production runs allowAdminChanges => false; never hand-edit the YAML.
  4. Data changes are content migrations (php craft migrate/create), tested on a copy of production - not CP clicking on live.
  5. Production runs a queue worker. Blitz regeneration, Formie emails and integrations, transform pre-generation, and resaves are all queue jobs.
  6. Fix queries, then cache. Blitz for public pages; on Blitz-cached pages drop {% cache %} (or set enableTemplateCaching false).
  7. Logic lives in module services, not Twig - services are testable.
  8. Stay on the latest Craft 5 patch. Craft ships regular Twig/RCE security fixes.

Version matrix

Package Craft 3 Craft 4 Craft 5 (current)
craftcms/cms 3.9 (EOL) 4.18 (EOL Apr 2026) Craft 5.x (5.11); Craft 6 in alpha
nystudio107/craft-seomatic 3.x 4.x SEOmatic 5
putyourlightson/craft-blitz 3.x 4.x Blitz 5 (5.13 needs Craft 5.6+)
verbb/formie 1.x 2.x Formie 3 (Formie 4 in beta)
Rich text Redactor Redactor or craftcms/ckeditor 3.x CKEditor plugin 5.x (needs Craft 5.10+; 4.x below that)
nystudio107/craft-vite 1.x 4.x craft-vite 5
nystudio107/craft-imageoptimize 1.x 4.x ImageOptimize 5
spacecatninja/imager-x 3.x 4.x Imager-X 6 (5.x still maintained)
codeception/codeception match core's require-dev match core's require-dev Codeception 5

Requirements for Craft 5: PHP 8.2+, MySQL 8.0.17+ / MariaDB 10.4.6+ / PostgreSQL 13+. Details and plugin upgrade notes: upgrades.md.

Everyday commands

Command (prefix ddev locally) Does
craft up Pending migrations + Project Config - run on every deploy
craft project-config/apply / project-config/rebuild Apply YAML to the DB / rebuild YAML from the DB
craft clear-caches/all Data, template, and asset caches
craft queue/run / queue/info / queue/retry all Work and inspect the queue
craft blitz/cache/refresh Refresh Blitz after template deploys (Blitz tracks content, not templates)
craft migrate/create <name> New content migration
craft make <type> Scaffold modules/plugins/components (craftcms/generator)
craft entrify/categories <group> Convert categories (or tags, global-set) to entries

Craft 5 content model

Concept What it is Craft 5 change
Section Single, Channel, or Structure; holds entry types + URI formats -
Entry type The unit of content shape Global and reusable across sections and Matrix fields
Field Reusable input Global, with multi-instance use in one layout
Matrix field Repeatable nested content Stores nested entries, not blocks
CKEditor field Rich text Can hold nested entries inline
Element partials _partials/entry/<typeHandle>.twig .render() renders nested entries through them
Project Config config/project/ YAML Source of truth - commit it

Pick the section type by shape: Single for one-off pages (home, contact), Channel for streams (news, events), Structure for hierarchies (pages, docs). Prefer flat entry types plus a Matrix "page builder" field over many near-identical sections. Starter shape: entry-type-field-layout.md.

Gotchas

Symptom Cause Fix
Listing page runs hundreds of queries Relation fetched per item .with() / .eagerly()
Change visible in CP, not on site Blitz/CDN serving cached HTML blitz.md
Form submissions save, emails never send Queue not running in production Queue daemon (performance.md)
Assets unstyled in production only Vite 5+ manifest is in dist/.vite/ Set manifestPath (craft-vite.md)
{% set seomatic.meta.seoTitle = ... %} does nothing set only reads {% do seomatic.meta.seoTitle('...') %}
Staging copy of the site got indexed / prod de-indexed SEOmatic environment wrong Check robots in view-source (seomatic.md)
Project Config conflicts between developers CP edits on shared/prod environments allowAdminChanges false outside local; one schema change per PR
Event handler fires several times per save Drafts, revisions, propagation Guard with ElementHelper::isDraftOrRevision() + propagating
craft.matrixBlocks() errors after upgrade Removed in Craft 5 craft.entries().field(...).owner(...)

Bundled resources

File Use
assets/entry-type-field-layout.md Content-modeling starter: section + entry type + Matrix-as-entries, mapped to Project Config
assets/craft-facts.json The version facts this skill documents (package, major, prose token)
scripts/check-craft-facts.py Staleness verifier: --offline (prose still states the facts) / --live (Packagist majors)

See also

  • ddev-ops (generic DDEV: version pinning, env files, snapshots and sanitised pulls, Mutagen, add-ons, Xdebug, and an auditor for .ddev/ mistakes)
  • laravel-ops (Composer/PHP tooling; Craft 6 is Laravel-based) · sql-ops (indexes behind slow orderBy) · nginx-ops (serving Craft, Blitz rewrites) · perf-ops (profiling) · tailwind-ops · playwright-ops (browser tests against the DDEV URL)
  • web-perf-ops (Core Web Vitals: CrUX/RUM first, then the failing subpart; Blitz, transforms, craft-vite critical CSS and SEOmatic/Formie script placement as INP/LCP levers)
  • frontend-upgrade-ops (Laravel Mix or Webpack to Vite via craft-vite, Vue 2 to Vue 3, Vue islands in Twig, and when a widget should become Alpine instead)
  • a11y-ops (WCAG 2.2 for Twig sites: heading levels across partials, asset alt text, Formie and CKEditor markup, multi-site lang; see its references/server-rendered-templates.md)
  • security-ops (Craft/Twig/PHP security: CSRF and Formie, allowAnonymous, devMode and the security key, GraphQL scoping, uploads, advisories and Craft 3/4 end of life; its references/craft-*.md, twig-*.md, php-*.md)
  • Craft 5 docs · Plugin Store · Craft security advisories

Why this shape: a 2026 survey of 57 Craft-agency repositories found Craft in 36 (Craft 5 ×17, 4 ×13, 3 ×6), DDEV in 36, SEOmatic in 33, Blitz 21, Formie 18, CKEditor 18, Laravel Mix 18 versus craft-vite 12, Tailwind 12, ECS 11, and Codeception 10. The references follow that frequency; upgrades matter because half the Craft sites were on an EOL major.