Introducing astro-entry-meta: drafts, reading time and git info for Astro collections
A new package that adds drafts, scheduled posts, reading time and git info to Astro content collections, and replaces astro-git-dates.
After I wrote astro-git-dates, I made a list of what else Eleventy and Hugo do that Astro doesn’t. Three of the ideas turned out to be the same idea. Each one changes a collection entry at build time, before the schema sees it. Three packages for that would be silly, so I made one: astro-entry-meta (external site).
TL;DR
- It replaces
astro-git-dates. Everygit Last Modifiedandgit Createdkeyword works the same, so switching is a new import and a new function name draft: true, a futurepublishDateor a pastexpiryDateleaves an entry out of the collection, like in Hugo (external site)- Computed fields: reading time, word count, an excerpt, the last author, an “Edit on GitHub” link. Anything you can work out from the body or from git
- One wrapper around your loader, no dependencies
A Zod schema can’t see an entry’s body, but a loader can. That’s why computed fields live here, and why a list page can show reading time without rendering every post. On this site it gives each post and code note a reading time, a word count and an edit link. draft: true posts are gone from the collection too, so getBlog() lost its draft filter. The site rebuilds every 12 hours, so a post with a publishDate appears by itself.
Add it to your site
pnpm add astro-entry-meta
Wrap the loader of each collection that should use it:
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
import { entryMeta, gitInfo, readingTime, type GitInfo } from 'astro-entry-meta';
const blog = defineCollection({
loader: entryMeta(glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }), {
// Show drafts and scheduled posts in `astro dev`
preview: import.meta.env.DEV,
computed: {
readingTime: ({ body }) => readingTime(body),
git: ({ filePath }) =>
filePath && gitInfo(filePath, { editUrl: 'https://github.com/me/site/edit/main/' }),
},
}),
schema: z.object({
title: z.string(),
date: z.date(),
// Computed fields must be in the schema, or it removes them
readingTime: z.number(),
git: z.custom<GitInfo>().optional(),
}),
});
export const collections = { blog };
Now the frontmatter can do this:
---
title: Coming soon
date: git Created
publishDate: 2026-12-01
---
And a page can show the rest:
<p>{post.data.readingTime} min read · <a href={post.data.git?.editUrl}>Edit on GitHub</a></p>
Two things to know. Git dates need the full history in CI, or every file gets the same date. On GitHub Actions, set fetch-depth: 0 on the checkout step. And a scheduled post only appears when you rebuild after its date.
Moving from astro-git-dates
- import { gitDates } from 'astro-git-dates';
+ import { entryMeta } from 'astro-entry-meta';
- loader: gitDates(glob({ ... })),
+ loader: entryMeta(glob({ ... })),
Nothing else changes.
The code is on GitHub (external site) and npm (external site). If you miss another Eleventy or Hugo feature in Astro, tell me.