← Back to Blog
development

Combining Singleton + Collection for Listing Pages

Some pages need both curated intro content (text, blocks, SEO) and a dynamic list of collection items. This combo pattern gives editors full control over the page structure while keeping entries maintainable.

The Pattern

  1. Singleton stores the listing page content: title, intro text, SEO fields, optional blocks
  2. Collection stores the repeatable items

Example: Services Listing

The services page uses this pattern. The /services page reads from the pages singleton (intro content) and the services collection (item cards).

---
import BaseLayout from '../layouts/BaseLayout.astro';
import { reader } from '../lib/reader';

// Singleton for page content
const page = await reader.collections.pages.read('services');
// Collection for items
const services = await reader.collections.services.all();

Implementing Your Own

Create a singleton for the listing page:

// singletons/projects-listing.ts
export const projectsListing = singleton({
  label: 'Projects',
  path: 'content/projects-listing',
  schema: {
    introTitle: fields.text({ label: 'Intro Title' }),
    introText: fields.text({ label: 'Intro Text', multiline: true }),
    ...seoFields,
  },
});

Create a collection for the items:

// collections/projects.ts
export const projects = collection({
  label: 'Projects',
  slugField: 'title',
  path: 'content/projects/*',
  schema: {
    title: fields.slug({ name: { label: 'Title' } }),
    description: fields.text({ label: 'Description', multiline: true }),
    url: fields.url({ label: 'URL' }),
  },
});

Then the Astro page combines both reads. The singleton content wraps the listing, and collection items are rendered in a grid.

Benefits

  • Editors edit intro text without touching code
  • Items remain individually manageable
  • SEO fields work per listing page
  • No hardcoded content