When speed, simplicity, and flexibility matter, Astro and Strapi make an ideal stack for modern content-driven websites.
In this post, We’ll explore how Astro differs from traditional React-based frameworks like Next.js and how the Astro + Strapi developer experience has been enhanced with a suite of open-source tools: Astro Strapi Loader, Astro Strapi Blocks Field, and the ready-to-go Astro Strapi Starter.
Introduction: Why Astro?
Astro has rapidly gained popularity for one core reason: performance by default.
Unlike React, Next.js, or Nuxt, which ship JavaScript by default, Astro follows a “zero JS runtime” philosophy. It renders static HTML during build time and ships only the JavaScript you explicitly opt into, usually via framework components (React, Vue, Svelte, etc.) or client directives. This makes Astro ideal for content-focused websites, where rendering speed and minimal client-side resources are key.
Key Astro differences vs Next.js & Nuxt:
Feature | Astro | Next.js | Nuxt |
---|---|---|---|
Default rendering | Static HTML | SSR/ISR | SSR/SSG/ISR |
JavaScript shipped | Zero by default | Required | Required |
Component model | Multi-framework (React, Vue, etc.) | React-only | Vue-only |
Client behavior | Opt-in (client:load ) | Implicit | Implicit |
Routing | File-based | File-based | File-based |
API endpoints | External | Built-in (API routes) | Built-in (server API) |
What makes Astro different?
Astro is designed to render the absolute minimum required at build time, shipping only static HTML unless interactivity is explicitly required. This leads to:
- Faster Time to First Byte (TTFB)
- Better Lighthouse scores
- Simplified deployment with static hosting (e.g., Netlify, Vercel, Cloudflare Pages)
- Smaller client bundles and less runtime overhead
When to use Astro over Next.js, Nuxt, and others?
Choose Astro when:
- Your site is primarily static and content-driven (blogs, marketing pages, documentation)
- You prioritize speed and SEO above everything else
- You want to compose components across multiple frontend frameworks
- You want to avoid bundling unnecessary JavaScript
Choose Next.js when:
- You need dynamic rendering per request (e.g., personalized content)
- You're building complex app-like user experiences with React
- You need built-in API routes tightly coupled to frontend logic
Choose Nuxt when:
- You're committed to the Vue ecosystem
- You want tight integration with Nuxt modules and SSR optimizations
- You need flexible rendering modes (SSR, SSG, hybrid)
While Next.js, Nuxt, and others are excellent choices for full-stack rendering and app-like UIs, Astro is engineered for speed-first, static-first sites. Its architecture minimizes runtime JavaScript and decouples rendering from interactivity in a way few other frameworks do.
Astro is particularly well-suited for content-focused sites, marketing pages, blogs, and documentation portals where SEO and performance are paramount. And when paired with Strapi, a headless CMS designed for developer productivity and custom content modeling, it creates an ideal stack for performance-first web delivery.
Astro Strapi Loader
🔗 VirtusLab-Open-Source/astro-strapi-loader
The @sensinum/astro-strapi-loader
package is a utility toolkit that brings structured Strapi content into Astro’s content collections system. It handles loading collections and single types from your Strapi instance and supports nested relationships, sorting, filtering, and integration with Astro’s native content layer.
Why use the loader?
Fetching and transforming content manually from Strapi in every Astro component can quickly become repetitive and error-prone, especially when dealing with nested relationships or large content models. The @sensinum/astro-strapi-loader
automates that work by generating Astro-compatible collections and providing ready-to-use helpers for efficient build-time data loading.
Instead of writing custom fetch logic and deeply nested .map()
or .reduce()
functions to normalize responses, the loader gives you a declarative interface that:
- Handles data population
- Normalizes the structure of responses
- Integrates with Astro’s content pipeline
- Speeds up development with fewer boilerplate fetches
This makes it the fastest way to pull in content from Strapi for static generation in Astro.
🖥️ Usage
Install the package:
npm install @sensinum/astro-strapi-loader
# or
yarn add @sensinum/astro-strapi-loader
Add the integration to your src/content.config.ts
:
1import { generateCollections } from '@sensinum/astro-strapi-loader';
2
3let strapiCollections: any = {};
4
5try {
6 strapiCollections = await generateCollections({
7 url: import.meta.env.STRAPI_URL,
8 token: import.meta.env.STRAPI_TOKEN,
9 }, [
10 {
11 name: "my-collection",
12 query: {
13 populate: {
14 // nested relationships
15 },
16 },
17 },
18 'yet-another-collection'
19 ]);
20} catch (error) {
21 console.error(error);
22}
23
24export const collections = {
25 ...strapiCollections,
26};
Use in your Astro component:
1---
2import { getCollection } from 'astro:content';
3import { fetchContent } from '@sensinum/astro-strapi-loader';
4
5// Basic usage with Astro Collections
6const myCollection = await getCollection('my-collection');
7
8// Basic usage with direct Strapi Content API fetch
9const myCollection = await fetchContent({
10 url: import.meta.env.STRAPI_URL,
11 token: import.meta.env.STRAPI_TOKEN,
12 contentType: 'my-collection',
13 queryParams: {
14 populate: {
15 // nested content
16 },
17 filters: {
18 // conditional logic
19 },
20 sort: ['publishedAt:desc'],
21 },
22});
23---
24
25<div>
26 { myCollection.map(item => (
27 <article>
28 <h2>{item.title}</h2>
29 <p>{item.description}</p>
30 </article>
31 )) }
32</div>
Environment setup
STRAPI_URL=https://cms.example.com
STRAPI_TOKEN=your-readonly-api-token
These environment variables allow the loader to authenticate and query your Strapi instance securely.
Highlights
- Seamless integration with Astro content collections
- Supports nested population, filters, and sorting
- Optional direct fetching, bypassing Astro’s content pipeline
- Works perfectly with CI/CD of most common providers
The loader bridges the gap between Astro’s static rendering model and Strapi’s rich, relational content model. It keeps your frontend clean while leveraging the full flexibility of Strapi’s content types.
This abstracts away repetitive fetch logic and enables clean separation between content modeling in Strapi and page logic in Astro.
Astro Strapi Blocks Field
🔗 VirtusLab-Open-Source/astro-strapi-blocks
Strapi's Blocks Field—formerly known as Rich Text Blocks—is a modern alternative to WYSIWYG editors or markdown fields. It allows content creators to compose rich content from predefined blocks such as paragraphs, media embeds, code snippets, quotes, buttons, and more.
Unlike traditional rich text, the Blocks Field stores structured JSON representing each block along with its configuration and content. This provides greater control over formatting, consistency, and styling on the frontend. Each block is defined by a type, and optionally includes metadata (e.g., alignment, caption, etc.).
How other frameworks render Blocks Field
In React-based frameworks like Next.js, developers typically build a custom renderer that maps each block to a React component. Alternatively, they can use the official Strapi Blocks React Renderer, which abstracts this mapping logic and provides default components for common block types.
Here’s what a manual implementation might look like:
1blocks.map((block, i) => {
2 switch (block.type) {
3 case 'paragraph':
4 return <p key={i}>{block.text}</p>;
5 case 'image':
6 return <Image key={i} src={block.url} alt={block.alt} />;
7 case 'code':
8 return <CodeBlock key={i} language={block.language}>{block.code}</CodeBlock>;
9 default:
10 return null;
11 }
12});
Rendering blocks in Astro
While this approach works well in React ecosystems, Astro is framework-agnostic by design. That’s where the @sensinum/astro-strapi-blocks
package comes in: it brings the same block rendering experience in a fully framework-agnostic way.
Instead of wiring up block-to-component mappings manually, developers can define renderers once and use them declaratively in .astro
files, without relying on a specific UI framework or runtime. This allows seamless integration into static builds with full control over HTML output, layout, and styling, while still honoring the structured block content authored in Strapi.
🖥️ Usage
Install the package:
npm install @sensinum/astro-strapi-blocks
# or
yarn add @sensinum/astro-strapi-blocks
Import and use the component in your .astro
template:
1---
2import { StrapiBlocks } from '@sensinum/astro-strapi-blocks';
3---
4
5<StrapiBlocks
6 data={strapiBlockData}
7 class="custom-class"
8 blocks={{
9 code: CustomCodeBlock,
10 heading: CustomHeadingBlock,
11 paragraph: CustomParagraphBlock
12 }}
13 theme={{
14 extend: { // 'extend' and/or 'overwrite'
15 paragraph: {
16 block: ['custom-paragraph-class'],
17 strong: ['custom-strong-class'],
18 italic: ['custom-em-class'],
19 link: ['custom-link-class']
20 },
21 heading: {
22 block: ['custom-heading-class']
23 },
24 list: {
25 block: ['custom-list-class']
26 },
27 quote: {
28 block: ['custom-quote-class']
29 },
30 code: {
31 block: ['custom-code-class']
32 },
33 image: {
34 block: ['custom-image-class']
35 }
36 }
37 }}
38/>
Highlights
- Framework-agnostic rendering of Strapi's Blocks Field in Astro
- Custom block mapping to your components (
paragraph
,heading
,code
, etc.) - Theming support using utility class injection via
theme.extend
ortheme.overwrite
- Optimized for static rendering without any runtime JS
This setup allows you to fully control how each block is rendered and styled, while preserving the authoring experience in Strapi.
Astro Strapi Starter
🔗 VirtusLab-Open-Source/astro-strapi-starter
Wondering if there’s an all-in-one solution to get started with Astro and Strapi by running a single command? Here comes the Starter!
To help developers hit the ground running, the Astro Strapi Starter project provides a ready-made template that wires together:
- Astro + TypeScript
- Astro Strapi Loader
- Astro Strapi Blocks
- Dynamic Zone rendering examples
- CMS image integration and usage
🖥️ Usage
- Use a starter template
npm create astro@latest -- --template VirtusLab-Open-Source/astro-strapi-starter
# or
yarn create astro --template VirtusLab-Open-Source/astro-strapi-starter
- Environment Variables Setup Create a
.env
file in the root directory:
# Strapi Configuration
STRAPI_URL=http://localhost:1337
STRAPI_TOKEN=your_strapi_api_token_here
- Run the Project
npm run dev
# or
yarn dev
You’ll get a clean, performant site that reflects real-world best practices in content modeling, block-based rendering, and Astro build optimization. By bundling preconfigured integrations, this starter saves hours of setup time. It’s perfect for teams who want:
- A unified architecture out of the box
- Minimal configuration to connect Astro with Strapi
- A reliable starting point that supports scale
Instead of boilerplate and guesswork, you get a launch-ready baseline aligned with performance and maintainability goals.
Summary
Astro and Strapi are a perfect match for developers who want control, performance, and flexibility. This article has demonstrated how combining Astro’s static-first, zero-JS-by-default architecture with Strapi’s headless CMS capabilities results in an ultra-performant, developer-friendly stack.
With Astro, you gain full control over what ships to the browser, producing lightning-fast, SEO-optimized pages. Unlike traditional JavaScript-heavy frameworks like Next.js or Nuxt, Astro prioritizes HTML output first, reducing unnecessary runtime overhead.
Strapi, on the other hand, offers a best-in-class content modeling and editorial experience. Editors can define structured data models and compose pages visually using the Blocks Field. It strikes a great balance between developer flexibility and non-technical usability.
We’ve explored how the ecosystem of open-source tools created by VirtusLab takes this integration even further:
- @sensinum/astro-strapi-loader allows seamless connection between Astro and Strapi, with support for nested relationships, filters, and sorting.
- @sensinum/astro-strapi-blocks brings structured, rich text to Astro without coupling to a specific frontend framework.
- The Astro Strapi Starter accelerates project setup by offering a ready-made, scalable boilerplate with zero configuration fuss.
Why this matters
Together, these tools remove the friction of setting up and scaling content-driven websites. Whether you're building a marketing website, documentation hub, blog platform, or editorial site, this stack:
- Encourages performance-first development
- Simplifies frontend integration
- Keeps content flexible and maintainable
- Works well with static hosting, CI/CD pipelines, and headless best practices
Built from real-world needs
The Astro Strapi Starter, along with both the @sensinum/astro-strapi-loader
and @sensinum/astro-strapi-blocks
packages, are the direct outcomes of real-world implementation work done for the sensinum.com website. They reflect best practices, architectural decisions, and performance-focused techniques validated in production. What you get in these tools is not a demo or an abstract idea; a final solution went through the whole process from the need to the working live website of a Tech Craftmanship Boutique brought to you by the VirtusLab Group.
Final thoughts
If your goals include fast time-to-interactive, smooth content workflows, and clean architecture, Astro + Strapi + these tools offer one of the most efficient and future-proof combinations in the Jamstack ecosystem.
To recap:
- Astro offers unmatched speed by shipping zero JS by default.
- Strapi empowers editors with a composable content model.
- Astro Strapi Loader makes fetching content easy.
- Astro Strapi Blocks unlock rich block rendering from the Strapi Rich Text Block.
- Astro Strapi Starter gives you a production-ready base to build on.
Whether you're building marketing sites, blogs, or content-rich apps, this stack will keep both developers and content teams moving fast.
Resources
- @sensinum/astro-strapi-loader – Content loader for Strapi collections and single types
- @sensinum/astro-strapi-blocks – Framework-agnostic renderer for Strapi’s Blocks Field
- Astro Strapi Starter – Production-ready template to kickstart your Astro + Strapi project
A multi-task Polish national with more than 12 years experience, Head of Frontend Engineering at VirtusLab. He is focusing on big things in every detail, supported by a team of around 50 engineers that keep pushing the digital transformation of their clients forward day by day. After hours (if that kind of word is even valid) a full-time dad and first sparring partner/teammate of future wannabe Formula 1 driver (privately his 7 years old son that trains karting).