Content model
How content is structured in this site: which collections exist, which fields they use, and the conventions that keep templates and listings consistent.
Collections in this site
Collections are defined in /src/content/config.ts. Content entries live in /src/content/<collection>/.
| Collection | Folder | Used for |
|---|---|---|
services | /src/content/services/ | Service pages and service listings (including homepage sections) |
portfolio | /src/content/portfolio/ | Case studies and the portfolio index |
thoughts | /src/content/thoughts/ | Thoughts/blog posts and the thoughts index |
resources | /src/content/resources/ | Resources and the resources index |
clients | /src/content/clients/ | Client entries used by the client logo grid |
pages | /src/content/pages/ | Generic page metadata used across layouts/templates |
Where content lives
Content entries live in /src/content/. Each collection has its own folder (for example /src/content/portfolio/).
Conventions
- Filenames matter — in most cases the entry slug defaults to the filename.
- Frontmatter is validated — schemas in
/src/content/config.tsdecide which fields are allowed/required. - Images are imported and optimised — image fields defined with
image()expect an asset in/src/assets/images/.
Services
Services are the primary building blocks for service pages and navigation. They are also used to tag portfolio entries.
Key fields
title— full name.slug(optional) — URL override (defaults to filename).order— controls ordering in listings.shortLabel,heading,teaser,description— copy used across the site.icon— image metadata (from/src/assets/images/).
Adding a new service
- Create a new file in
/src/content/services/. - Set an
ordervalue so it appears in the right place. - Provide an
iconimage (in/src/assets/images/) that matches the frontmatter reference.
Portfolio
Portfolio entries are case studies. They can reference one or more services for filtering and “related work”.
Key fields
title,subtitledate(optional) — used for sorting (newest first).client(optional)excerpt(optional)featuredImage(optional) — image metadata for listing thumbnails.services(optional) — referencesservicescollection items.quote,quoteAttribution,quoteBackground(optional) — for in-page callouts.
Service tagging
Portfolio entries can be tagged with multiple services. This powers filtering on the portfolio index and supports “related case studies” lists.
Thoughts
Long-form posts. These support optional “further reading” and an optional featured link block.
Key fields
title,subtitle(optional)date(optional),author(optional)categories(optional)excerpt(optional)heroImage(optional),heroColor(optional)furtherReading(optional),furtherReadingTitle(optional)featuredLink(optional) — includes a screenshot filename and optional alt text.
Resources
Resources are similar to thoughts, but with a simpler metadata shape.
Key fields
title,subtitle(optional)date(optional),author(optional)excerpt(optional)heroImage(optional),heroColor(optional)
Clients
Client entries feed the client logo grid. Logos are typically named to match the client slug and stored in /src/assets/images/.
Key fields
titlelink(optional)logo(optional) — currently a string field.
Pages
Generic page metadata used by templates/layouts where needed.
Key fields
titlesubtitle(optional)description(optional)
Querying patterns
Most listings load entries with getCollection, then filter/sort in code.
Typical query
import { getCollection } from 'astro:content';
const allPortfolio = await getCollection('portfolio');
const sorted = allPortfolio
.filter((entry) => entry.data.featuredImage)
.sort((a, b) => (b.data.date?.valueOf() ?? 0) - (a.data.date?.valueOf() ?? 0)); Images
Some frontmatter fields are validated as image() types. Those expect a file in /src/assets/images/ and will be optimised by the site’s shared image utilities/components.
What to use for new entries
- Prefer image fields typed as
image()where possible (typed, optimisable, and harder to break). - Keep filenames stable to avoid broken references.
- Provide meaningful alt text at render time (for example when using hero images).
References between content
Some collections reference others for stronger relationships. For example, portfolio entries use reference('services') so service filtering is reliable and type-safe.
Practical impact
- Renaming a service can affect linked portfolio entries (because they reference the service entry).
- Deleting a service may invalidate portfolio entries that reference it.