timis
Start a project
← all posts updated 28 Sept 2026 · wordpress · sage · tailwind

Roots Sage 11: why we build custom WordPress themes on it

Sage 11 brings Vite, Tailwind CSS 4, Laravel Blade and a theme.json generated from your Tailwind config. Why it is our starting point for every custom WordPress theme.

The starter theme you pick shapes everything that follows on a WordPress project: how fast the team can build, how the block editor behaves, how the site performs and how painful it is to maintain three years later. We have tried most of the options, and almost every custom WordPress theme we build starts from Roots Sage. This post was first written for Sage 10; it is now updated for Sage 11, which replaced the whole build pipeline.

What Sage is

Sage is an open-source WordPress starter theme maintained by Roots, the team behind Bedrock and Trellis. It is not a parent theme and not a page builder. It is a clean starting point with a modern workflow:

  • Laravel Blade templates and components instead of PHP mixed with HTML
  • Vite for the dev server and production builds, with hot module replacement
  • Tailwind CSS 4 out of the box
  • Acorn, which brings Laravel’s service container, config, views and Artisan-style commands into WordPress
  • Block editor support built in, including a theme.json generated from your Tailwind config

What changed in Sage 11

Sage 11 was released in March 2025 together with Acorn 5. If you know Sage 10, these are the changes that matter:

Sage 10 Sage 11
Build tool bud.js (webpack) Vite (laravel-vite-plugin + @roots/vite-plugin)
Package manager Yarn by default npm (npm run dev, npm run build)
Tailwind v3, tailwind.config.js v4, configured in CSS with @theme
theme.json generated by a bud extension generated by wordpressThemeJson() in vite.config.js
Assets in Blade @asset() / bundle() @vite([...]) and Vite::asset()
Acorn bootstrapping \Roots\Acorn\Bootloader Application::configure()->withProviders([...])->boot()
PHP 8.1+ with Acorn 4 8.2+ (the current main branch asks for 8.3 and Acorn 6)

The result is a much faster dev server, instant CSS updates in the browser and in the block editor, and a build config that fits on one screen.

1. Blade templates instead of PHP spaghetti

Classic WordPress themes mix logic and markup in the same files, which gets hard to manage on larger projects:

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
  <h2><?php the_title(); ?></h2>
  <?php the_content(); ?>
<?php endwhile; endif; ?>

Blade separates logic from presentation, supports layouts and reusable components, and escapes output by default, which removes a whole class of XSS mistakes:

@while(have_posts()) @php(the_post())
  <h2>{{ get_the_title() }}</h2>
  @php(the_content())
@endwhile

A button becomes <x-button href="/contact/">Start a project</x-button>, defined once and used everywhere. View composers keep data preparation out of the templates, so designers and developers can work on the same component without stepping on each other.

2. The block editor matches the front end

This is the part clients notice. Sage 11’s Vite config includes the wordpressThemeJson() plugin, which reads your Tailwind theme (colours, font families, font sizes, border radius) and writes it into theme.json. WordPress then uses that file to configure the editor:

  • Consistent styling: the colour palette and type scale in the editor are exactly the ones on the site. Editors cannot pick an off-brand colour because it is not in the list.
  • Less CSS: defaults live in theme.json instead of being overridden with more CSS, so pages ship less code.
  • Editor HMR: resources/css/editor.css and resources/js/editor.js are loaded into the block editor, and changes appear there without a reload while you develop.

For custom blocks we pair Sage with ACF Composer or native blocks registered from the theme. Each block gets a Blade view, so a pricing table, a testimonial slider or a case-study grid is a small, structured piece of code the marketing team can use without ever breaking the layout. Les Cours Bellerive, a bilingual condo sales site we have run since 2020, is built this way: Sage, Blade templates and ACF field groups kept in code.

3. A build pipeline you don’t have to fight

Sage 11’s vite.config.js is short: Tailwind, the Laravel Vite plugin with four entry points (app and editor CSS/JS), wordpressPlugin() to handle WordPress script dependencies, and wordpressThemeJson(). Adding TypeScript, Sass or a front-end framework is a regular Vite plugin, not a custom webpack loader. Production builds are hashed and loaded through Vite’s manifest, so browsers can cache assets for a year.

4. Laravel inside WordPress, through Acorn

Acorn is what makes Sage feel like a modern application rather than a theme. You get service providers, a config directory, Laravel collections, caching, and wp acorn commands for things like clearing the view cache or scaffolding components. On larger sites it lets us organise custom post types, integrations and business logic the way we would in a Laravel app, and test them the same way.

5. Longevity

Sage has been maintained for over a decade and has been rewritten several times to keep up with the ecosystem: from Gulp to webpack, to bud.js, and now Vite. The public API a theme relies on (Blade views, composers, Acorn providers) has stayed stable enough that upgrading is a bounded job rather than a rebuild.

Getting started with Sage 11

You need PHP 8.2+ (8.3 for the current main branch), Composer and Node.js 20.19+ or 22.12+.

# inside wp-content/themes (or web/app/themes on Bedrock)
composer create-project roots/sage my-theme
cd my-theme
npm install

Set base in vite.config.js to the public build path of your theme, for example /wp-content/themes/my-theme/public/build/ on a standard install or /app/themes/my-theme/public/build/ on Bedrock. Then:

npm run dev    # dev server with hot reload
npm run build  # production build to public/build

If WordPress shows “Vite manifest not found”, the assets have not been built yet. Run npm run build once.

Upgrading a Sage 10 theme

Moving a Sage 10 theme to 11 is mostly mechanical. The order that causes the least pain:

  1. Update Acorn and switch functions.php to Application::configure().
  2. Replace bud.config.js with vite.config.js and move from Yarn to npm.
  3. Replace @asset() and bundle() calls with @vite() and Vite::asset().
  4. Move the Tailwind 3 config into CSS (@theme) and check every utility that changed in v4.
  5. Rebuild and compare theme.json output, since editor colour and font slugs can change.

Budget more time for step 4 than for the rest combined.

When Sage is not the right choice

Sage is built for developers. If the site will be assembled entirely by non-developers in a page builder, or if the team has no one comfortable with Composer and a build step, a block theme or a simpler setup will be easier to own. For a marketing site that a team edits every week and a developer maintains for years, we have not found anything better.

Need help with a Sage theme?

We build and maintain custom WordPress themes on Sage for companies in Europe and North America, and we can take over an existing Sage theme that needs an upgrade. See our WordPress development services or get in touch.

Have a project in mind?

Tell us what you are building. We reply within one business day with next steps — or an honest “not a fit”.