npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@astroblocks/astro-blocks

v2.0.0

Published

Block-based content CMS integration for Astro with admin panel, page builder, menus, SEO and cache invalidation.

Readme


Why AstroBlocks

  • Edit pages in /cms without adding a database.
  • Keep full control over the rendered HTML by using your own Astro components.
  • Define blocks with a small, explicit schema contract.
  • Store content in data/*.json and uploads in public/uploads/.
  • Generate sitemap-index.xml and robots.txt from the same content source.
  • Keep consumer imports explicit and type-safe.

Block Editor

The page editor is the core of AstroBlocks. It is designed as a compact block builder so content, SEO and structure can be managed from a single workflow.

  • Block-first editing: pages are built by stacking your own Astro components as CMS blocks.
  • Compact builder UI: block cards show the most relevant context first and keep advanced editing one step away.
  • SEO and content together: title, slug, indexability and SEO metadata live in the same editing surface.
  • Ordering without friction: blocks can be reordered, duplicated and removed directly from the editor.

Requirements

| Dependency | Version | | --- | --- | | Node.js | 18+ | | Astro | 6+ | | Adapter | @astrojs/node 10+ |

AstroBlocks alpha defaults to SSR public pages + Astro experimental cache. Use output: 'static' plus a server adapter so /cms, /cms/api, /robots.txt, /sitemap-index.xml and CMS-managed public pages can run dynamically.


Install

From npm

npm install @astroblocks/astro-blocks
npm install @astrojs/node

From a local tarball

Use this when you want to validate a locally built package:

npm install /absolute/path/to/astroblocks-astro-blocks-<version>.tgz

The tarball flow is documented in LOCAL_PACKAGE_TESTING.md.


Recommended Imports

Keep imports split by responsibility:

import astroBlocks from '@astroblocks/astro-blocks';
import { defineBlockSchema } from '@astroblocks/astro-blocks/contract';
import { getConfig } from '@astroblocks/astro-blocks/getConfig';
import { getI18nMeta } from '@astroblocks/astro-blocks/getI18nMeta';
import { getLanguages } from '@astroblocks/astro-blocks/getLanguages';
import { getMenu } from '@astroblocks/astro-blocks/getMenu';
  • @astroblocks/astro-blocks is the Astro integration entrypoint.
  • @astroblocks/astro-blocks/contract is the public block-schema contract.
  • @astroblocks/astro-blocks/getConfig reads CMS parameters from data/configs.json at runtime.
  • @astroblocks/astro-blocks/getI18nMeta builds hreflang, html lang and OpenGraph locale metadata from AstroBlocks i18n context.
  • @astroblocks/astro-blocks/getLanguages reads configured content languages for locale switchers.
  • @astroblocks/astro-blocks/getMenu is the runtime helper for reading menu items inside your site.

Quick Start

1. Configure Astro

import { defineConfig, memoryCache } from 'astro/config';
import node from '@astrojs/node';
import astroBlocks from '@astroblocks/astro-blocks';
import { schema as heroSchema } from './src/components/Hero.schema.ts';

export default defineConfig({
  output: 'static',
  adapter: node({ mode: 'standalone' }),
  experimental: {
    cache: {
      provider: memoryCache(),
    },
  },
  integrations: [
    astroBlocks({
      layoutPath: './src/layouts/Layout.astro',
      blocks: [heroSchema],
    }),
  ],
});

2. Define a block component

---
interface Props {
  title: string;
  subtitle?: string;
}

const { title, subtitle } = Astro.props;
---

<section>
  <h1>{title}</h1>
  {subtitle && <p>{subtitle}</p>}
</section>

3. Define its schema

import { defineBlockSchema } from '@astroblocks/astro-blocks/contract';

export const schema = defineBlockSchema(
  {
    name: 'Hero',
    icon: 'Layout',
    items: {
      title: { type: 'string', label: 'Title', required: true },
      subtitle: { type: 'text', label: 'Subtitle' },
    },
  },
  new URL('./Hero.astro', import.meta.url).href
);

Array fields are also supported for repeatable content:

items: {
  tags: {
    type: 'array',
    label: 'Tags',
    minItems: 1,
    maxItems: 6,
    item: { type: 'string', label: 'Tag' },
  },
  faqs: {
    type: 'array',
    label: 'FAQs',
    item: {
      type: 'object',
      label: 'FAQ',
      summaryField: 'question',
      fields: {
        question: { type: 'string', label: 'Question', required: true },
        answer: { type: 'text', label: 'Answer', required: true },
      },
    },
  },
}

4. Provide a layout for CMS-rendered pages

Your layout receives these props:

| Prop | Meaning | | --- | --- | | title | Final page title | | description | Final meta description | | canonical | Canonical URL | | noindex | Whether the page is non-indexable | | site | Data from data/site.json | | seo | Final SEO object, including absolute image when present | | i18n | i18n context for the current page (locale, defaultLocale, alternates) |

Example:

---
import { getMenu } from '@astroblocks/astro-blocks/getMenu';
import { getI18nMeta } from '@astroblocks/astro-blocks/getI18nMeta';

const { title, description, canonical, noindex, seo, site, i18n } = Astro.props;
const menu = await getMenu('main');
const i18nMeta = getI18nMeta(i18n, { baseUrl: site?.baseUrl });
---

<html lang={i18nMeta?.htmlLang || 'en'}>
  <head>
    <title>{title}</title>
    {description && <meta name="description" content={description} />}
    {canonical && <link rel="canonical" href={canonical} />}
    {noindex && <meta name="robots" content={seo?.nofollow ? 'noindex, nofollow' : 'noindex'} />}
    {seo?.image && <meta property="og:image" content={seo.image} />}
    {i18nMeta?.alternates.map((entry) => (
      <link rel="alternate" hreflang={entry.hrefLang} href={entry.href} />
    ))}
    {i18nMeta?.ogLocale && <meta property="og:locale" content={i18nMeta.ogLocale} />}
    {i18nMeta?.ogLocaleAlternate.map((entry) => (
      <meta property="og:locale:alternate" content={entry} />
    ))}
  </head>
  <body>
    <nav>
      {menu.map((item) => <a href={item.path}>{item.name}</a>)}
    </nav>
    <slot />
  </body>
</html>

In SSR mode (publicRendering: 'server'), AstroBlocks can use Accept-Language on / to redirect to a non-default enabled locale when available. Locale preference is then persisted with a cookie so users can switch language and keep their chosen locale.


Data Model

AstroBlocks creates and reads these files in the consumer project root:

| Path | Purpose | | --- | --- | | data/pages.json | Pages, slug, status, blocks, indexable, SEO | | data/site.json | Site name, base URL, favicon, logo, colors, default SEO | | data/menus.json | Menus and nested menu items | | data/redirects.json | Manual redirect rules (from, to, 301/302, enabled) | | data/configs.json | Global key/value parameters consumable from code (key, value, description) | | data/languages.json | Content languages (code, label, enabled, isDefault) | | data/users.json | CMS users | | public/uploads/ | Uploaded files |

You can version these files in your project repository if that fits your workflow.


CMS Routes

| Route | Purpose | | --- | --- | | /cms | Dashboard | | /cms/pages | Pages | | /cms/redirects | Redirect rules | | /cms/configs | Global parameters | | /cms/menus | Menus | | /cms/settings | Site settings | | /cms/users | Users | | /cms/languages | Content languages | | /cms/cache | Invalidate AstroBlocks cache |

API routes are available under /cms/api/*.


Menus In Your Site

---
import { getMenu } from '@astroblocks/astro-blocks/getMenu';

const mainMenu = await getMenu('main', { locale: 'es' });
---

<nav>
  {mainMenu.map((item) => (
    <a href={item.path}>{item.name}</a>
  ))}
</nav>

Returned menu items have this shape:

type MenuItem = {
  name: string;
  path: string;
  children?: MenuItem[];
};

Languages In Your Site

---
import { getLanguages } from '@astroblocks/astro-blocks/getLanguages';

const { languages, defaultLocale } = await getLanguages();
---

<nav>
  {languages.map((language) => (
    <a href={language.code === defaultLocale ? '/' : `/${language.code}`}>
      {language.label}
    </a>
  ))}
</nav>

Config Parameters In Your Site

---
import { getConfig, getConfigMap } from '@astroblocks/astro-blocks/getConfig';

const mapsKey = await getConfig('GOOGLE_MAPS_API_KEY');
const allConfigs = await getConfigMap();
---
  • getConfig(key) matches keys case-insensitively and returns string | undefined.
  • getConfigMap() returns every configured key/value pair as an object.
  • In SSR mode, updates from /cms/configs are available after save + cache invalidation.
  • In publicRendering: 'static', values are fixed at build time until the next rebuild.

Plugin Options

| Option | Description | | --- | --- | | layoutPath | Path to the Astro layout used when AstroBlocks renders a page | | blocks | Array of block schemas imported from your .schema.ts files | | publicRendering | 'server' by default in alpha. Use 'static' to opt back into prerendered public pages | | cache | Cache behavior for SSR public pages. Enabled by default in alpha when the consumer configures an Astro cache provider | | i18n.routingStrategy | Public routing contract for localized paths ('path-prefix' in this alpha) |

Cache Provider

AstroBlocks does not configure Astro's cache provider for you. The consumer project must opt into Astro's experimental cache explicitly:

import { defineConfig, memoryCache } from 'astro/config';

export default defineConfig({
  experimental: {
    cache: {
      provider: memoryCache(),
    },
  },
});

Without a provider, AstroBlocks will keep serving pages in SSR mode, but caching and invalidation will be inactive.

Static Opt-Out

If you want the public site to stay prerendered:

astroBlocks({
  layoutPath: './src/layouts/Layout.astro',
  blocks: [heroSchema],
  publicRendering: 'static',
});

Redirect rules are SSR-only in this alpha MVP. When publicRendering: 'static', redirects configured in /cms/redirects are not applied.


Using with AI Tools

@astroblocks/astro-blocks ships a consumer-facing AI context file (AGENTS.consumer.md) inside the npm tarball. AI coding assistants (Claude, Copilot, Cursor, Windsurf, etc.) can read this file to understand the integration API, block development patterns, admin routes, and environment variables without you having to explain them manually.

One-line setup:

npx astro-blocks init-ai

This command detects your project's AGENTS.md or CLAUDE.md (creating AGENTS.md if neither exists) and appends a reference to the consumer context file. The reference points to the installed package:

node_modules/@astroblocks/astro-blocks/AGENTS.consumer.md

The context file is auto-versioned with the installed package — when you upgrade @astroblocks/astro-blocks, re-run npx astro-blocks init-ai to refresh the reference.

Use --copy to embed the full content inline instead of a reference link:

npx astro-blocks init-ai --copy

Consumer Troubleshooting

Content changes do not appear on the public site

CMS-managed public pages are served in SSR by default in alpha. If changes do not appear:

  • make sure the page is published
  • make sure your project is using the AstroBlocks catch-all route and not a conflicting file in src/pages/
  • make sure your server adapter is configured correctly
  • make sure Astro experimental cache is configured if you expect cache invalidation to work

In development, Astro exposes the cache API but does not cache real responses. Validate cache behavior in a built project or preview-like environment.

Regenerate site runs a fresh build artifact, but it is not required to see content changes during development.

The CMS routes do not work

Check all of these:

  • you are using Astro 6+
  • you have a server adapter configured
  • output: 'static' is enabled
  • the integration is included in astro.config.*

My home page is not coming from the CMS

If your project already has src/pages/index.astro, Astro may serve that file instead of the CMS home page.

The layout receives a relative SEO image

AstroBlocks already converts relative seo.image values to absolute URLs before passing them to your layout. Use seo.image directly for og:image and twitter:image.

I want to validate a local build before publishing

Use the tarball flow documented in LOCAL_PACKAGE_TESTING.md.


For Maintainers

This README is intentionally consumer-focused.

If you are working on AstroBlocks itself, use:

  • DEVELOPING.md for build, workspace, playground and release workflow
  • AGENTS.md for repository-specific implementation rules