v0.25
August 12, 2025

Introducing “slice components”

We’ve re-thought the API for fine-grained component rendering.

by Tyler Lawson
senior engineer at second spectrum

We’re happy to announce Waku v0.25 with a brand new API: Slice Components!

We feel the Slices API solves issues reported with the now deprecated Page Part components while also unlocking brand new flexibility with render patterns!

Components are re-useable across pages

Slices are components that are defined in the src/pages/_slices directory. This allows us to re-use slices across pages as any other component would be used.

src/pages
 ├── _slices
 │   ├── one.tsx
 │   └── two.tsx
 └── some-page.tsx

And some-page.tsx will be written something like this:

import { Slice } from 'waku';

export default function SomePage() {
  return (
    <div>
      <Slice id="one" />
      <Slice id="two" />
    </div>
  );
}

export const getConfig = () => {
  return {
    render: 'static',
    slices: ['one', 'two'],
  };
};

Please notice: slices must be specified with each of the slice ids in order for Waku to know how to bundle your page without any compiler magic.

The slice id will be the filename. If slices are nested like src/pages/_slices/one/two.tsx, the id will be one/two.

An example for src/pages/_slices/one.tsx:

export default function SliceOne() {
  return <p>🍕</p>;
}

export const getConfig = () => {
  return {
    render: 'static', // default is 'static'
  };
};

We’re really happy with the new approach and how it will allow simply importing and assembling your components like normal components, while also specifying alternate rendering.

Lazy Slice Components

lazy Slice Components are a new addition with the Slices API. They are Waku’s take on the server islands feature from Astro. lazy allows components to be requested independent from the page they are used on. This is useful for components will be dynamically rendered on otherwise static pages and layouts.

If we re-use the example above, it could be written like this:

import { Slice } from 'waku';

export default function SomePage() {
  return (
    <div>
      <Slice id="one" />
      <Slice id="two" lazy fallback={<p>Two is loading...</p>} />
    </div>
  );
}

export const getConfig = () => {
  return {
    render: 'static',
    slices: ['one'], // Note: `two` is lazy so it is not included with the page config
  };
};

This makes it so that now you can have a dynamic Slice component for slice two here, while the rest of the page is static.

Some breaking changes

We’ve standardized on the following defaults: pages, layouts, and slices are all static by default. API routes are dynamic by default.

This comes with the explicit change of pages default render to 'static'. So any pages that do not currently use getConfig should add:

export const getConfig = () => {
  return {
    render: 'dynamic',
  } as const;
};

There’s more to come

We’re keeping Waku Router minimal and making it even more powerful with this release. We’re really excited to see what you can build with Slices and would love to hear from you on our Discord server, GitHub discussions, or around the web.

P.S., We have a few more things coming soon!

designed bycandycode alternative graphic design web development agency San Diego