cnvs/canvas
Canvas is a lightweight Laravel publishing platform for creating and managing a beautiful blog with ease. It offers a clean admin interface, Markdown writing, tags, customizable templates, and SEO-friendly pages, all seamlessly integrated into your Laravel application.
post-{uuid}. That converts a previously opaque, non-indexable URL pattern into readable, keyword-bearing ones — which matters for SEO, social previews, and sharing. Two caveats worth recording as decisions: (a) the fix applies to newly created posts, so if we adopt now we should decide our stance on any pre-existing post-{uuid} rows (leave, backfill, or redirect), and (b) slug derivation is now a behavior we depend on, so a future change to slug rules becomes a potential breaking change to live URLs we'd need to plan redirects around.published_at in ISO-8601), we can scope a v1 with the roles as shipped and defer custom approval chains, per-team permissions, or legal review steps to a later phase — with a clear signal of what we'd be customizing.en source-of-truth catalog. If we expand into non-English markets, UI localization isn't a project — content localization still is (and remains our problem).resources/dist/) means hosts get a working admin UI with no Node build step in our CI. That's a real ops decision: adopt as-is and treat UI as vendor-owned, or budget for a fork if our design system or admin shell must match ours. Note that every release — including patch releases like this one — ends with php artisan canvas:publish, which republishes those assets. A fork therefore has an ongoing re-apply cost, not a one-time one.Adopt when all of the following hold:
illuminate/* contracts only and is not a fit for Lumen, Symfony, or an older Laravel LTS we can't upgrade.resources/js/ and committing our own dist.composer update → php artisan canvas:migrate → php artisan canvas:publish. That's a self-supported dependency — MIT, no SLA, no paid tier — and someone on the team must own running those steps and reading .github/UPGRADE.md before each bump.Look elsewhere when:
For executives — the one-liner: We can have a production-grade, self-hosted publishing platform in our existing Laravel app for the cost of an integration sprint, instead of a CMS license, a headless-CMS subscription, or a homegrown admin build. MIT licensed, data stays in our database, no vendor lock-in — if we ever walk away, the content is just rows in our own schema.
The trade we're making: we take on maintenance ownership (upgrades, asset republishing) in exchange for zero recurring cost, full data control, and no second platform to secure, back up, and staff. That's the right trade for owned-media content, which is not a differentiated system for us.
For engineering — why it's low-friction: it's a package, not an app. Dependencies are illuminate/* contracts, not laravel/framework, so it composes into the host rather than imposing a scaffold. It has its own Pest/Testbench suite with a 98% coverage floor, static analysis at Larastan level 6, and documented PR gates — quality signals we can audit. Admin assets ship prebuilt, so no Node toolchain enters our deploy path. There's an optional HasCanvasAccess concern rather than a forced user-model change.
For engineering — the honest caveats: single-package maintenance risk and no support contract; every upgrade requires reading UPGRADE.md, running canvas:migrate, and republishing assets. The just-shipped v7.2.3 illustrates the shape of it well: a genuinely useful fix (new post slugs now follow the title rather than post-{uuid}) that we would want, delivered in a release that still asks us to run migrate + publish. That's cheap, but it is ours to run, on our schedule, every time. Supported matrix is Laravel 12/13, so it constrains future framework choices; the admin UI is vendor-owned unless we fork; and slug behavior is now something we depend on, so we should own redirects if the rule ever changes.
Ask: approve a timeboxed spike — install in a staging branch, wire auth and roles, publish one post end-to-end, confirm slug generation and the canvas:migrate/canvas:publish steps fit our deploy pipeline, validate the webhook path into our existing automation, and report back on integration cost and upgrade ergonomics. Decision to adopt or reject comes from that spike, not from this memo.
How can I help you explore Laravel packages today?