This guide covers the rules and conventions for creating new posts in AstroPaper — file placement, frontmatter fields, images, and syntax highlighting.

Photo by Pixabay
Table of contents
Open Table of contents
Creating a Blog Post
To write a new blog post, create a markdown (or MDX) file inside the src/content/posts/ directory.
You can organize posts into subdirectories to make content easier to manage. The subdirectory name becomes part of the post URL. For example, src/content/posts/2025/example-post.md will be available at /posts/2025/example-post.
If you want a subdirectory for organization only, without it affecting the URL, prefix the folder name with an underscore (_).
# Example: post file paths and their URLs
src/content/posts/very-first-post.md -> mysite.com/posts/very-first-post
src/content/posts/2025/example-post.md -> mysite.com/posts/2025/example-post
src/content/posts/_2026/another-post.md -> mysite.com/posts/another-post
src/content/posts/docs/_legacy/how-to.md -> mysite.com/posts/docs/how-to
src/content/posts/Example Dir/Dummy Post.md -> mysite.com/posts/example-dir/dummy-post
Files and directories prefixed with
_are excluded from routing. Use them for drafts, shared assets, or internal-only content.
Frontmatter
Frontmatter is the main place to store metadata about a blog post. It lives at the top of the file in YAML format. Read more about frontmatter and its usage in Astro documentation.
Here is the list of frontmatter properties for each post:
| Property | Description | Remark |
|---|---|---|
| title | Title of the post. (h1) | required* |
| description | Description of the post. Used in post excerpt and site description of the post. | required* |
| pubDatetime | Published datetime in ISO 8601 format. | required* |
| modDatetime | Modified datetime in ISO 8601 format. (only add this property when a blog post is modified) | optional |
| author | Author of the post. | default = site.author |
| featured | Whether or not to display this post in the featured section of the home page. | default = false |
| draft | Mark this post as ‘unpublished’. | default = false |
| tags | Related keywords for this post. Written in array YAML format. | default = others |
| ogImage | OG image of the post. Useful for social media sharing and SEO. Can be a remote URL or an image path relative to the current folder. | default = site.ogImage or generated OG image |
| canonicalURL | Canonical URL (absolute), in case the article already exists on another source. | default = Astro.site + Astro.url.pathname |
| hideEditPost | Hide the edit-post button under the post title. Applies only to the current post. | default = false |
| timezone | Specify a timezone in IANA format for the current post. Overrides the global site.timezone config for this post only. | default = site.timezone |
Tip! You can get an ISO 8601 datetime by running
new Date().toISOString()in the console.
Only title, description, and pubDatetime fields in frontmatter must be specified.
Title and description (excerpt) are important for search engine optimization (SEO) and thus AstroPaper encourages you to include these in all blog posts.
If you omit tags in a blog post (in other words, if no tag is specified), the default tag others will be used as a tag for that post. You can set the default tag in src/content.config.ts:
// ...
tags: z.array(z.string()).default(["others"]), // replace "others" with whatever you want
// ...src/content.config.ts
Sample Frontmatter
Here is sample frontmatter for a post.
---
title: The title of the post
author: your name
pubDatetime: 2022-09-21T05:17:19Z
featured: true
draft: false
tags:
- some
- example
- tags
ogImage: ../../assets/images/example.png # src/assets/images/example.png
# ogImage: "https://example.org/remote-image.png" # remote URL
description: This is the example description of the example post.
canonicalURL: https://example.org/my-article-was-already-posted-here
---src/content/posts/sample-post.md
VS Code snippets (optional)
AstroPaper includes workspace snippets to speed up creating new posts:
- frontmatter: inserts the recommended frontmatter block
- template: inserts a basic post template (including
## Table of contents)
These snippets live in .vscode/astro-paper.code-snippets. If you use VS Code (or Cursor), they should be available automatically when you open the workspace.
Adding table of contents
By default, a post does not include any table of contents (TOC). To include one, write Table of contents as an h2 heading (## in Markdown) and place it where you want it to appear:
---
# frontmatter
---
Here are some recommendations, tips & tricks for creating new posts in AstroPaper blog theme.
## Table of contents
<!-- the rest of the post -->
Headings
There’s one thing to note about headings. AstroPaper blog posts use title (from frontmatter) as the main heading of the post. Therefore, the rest of the headings in the post should use h2 ~ h6.
This rule is not mandatory, but highly recommended for visual, accessibility, and SEO purposes.
Syntax Highlighting
AstroPaper uses Shiki as the default syntax highlighter, with @shikijs/transformers for enhanced fenced code blocks. If you don’t want to use the transformers, you can remove them:
pnpm remove @shikijs/transformers
// ...
import {
transformerNotationDiff,
transformerNotationHighlight,
transformerNotationWordHighlight,
} from "@shikijs/transformers";
export default defineConfig({
// ...
markdown: {
remarkPlugins: [remarkToc, [remarkCollapse, { test: "Table of contents" }]],
shikiConfig: {
themes: { light: "min-light", dark: "night-owl" },
defaultColor: false,
wrap: false,
transformers: [
transformerFileName(),
transformerNotationHighlight(),
transformerNotationWordHighlight(),
transformerNotationDiff({ matchAlgorithm: "v3" }),
],
},
},
// ...
});astro.config.ts
Storing Images for Blog Content
Here are two methods for storing images and using them inside a markdown file.
Note: If you need to style optimized images in markdown, you should use MDX.
Inside src/assets/ directory (recommended)
You can store images inside the src/assets/ directory. These images will be automatically optimized by Astro through the Image Service API.
You can use a relative path or alias path (@/assets/) to reference these images.
Example: suppose you want to display example.jpg whose path is src/assets/images/example.jpg.

<!-- OR -->

<!-- Using img tag or Image component won't work in markdown ❌ -->
<img src="@/assets/images/example.jpg" alt="something">
<!-- ^^ This is wrong -->
Technically, you can store images inside any directory under
src.src/assetsis just a recommendation.
Inside public/ directory
You can store images inside the public/ directory. Keep in mind that images stored in public/ remain untouched by Astro, meaning they will be unoptimized and you need to handle image optimization yourself.
For these images, use an absolute path. They can be displayed using markdown image syntax or an HTML img tag.
Example: assume example.jpg is located at public/assets/images/example.jpg.

<!-- OR -->
<img src="/assets/images/example.jpg" alt="something">
Bonus
Image compression
When putting images in a blog post (especially those in the public/ directory), it is recommended to compress them. This will affect the overall performance of the website.
Recommended image compression sites:
OG Image
The default OG image will be used if a post does not specify one. Though not required, an OG image relevant to the post should be specified in the frontmatter. The recommended size for OG images is 1200 X 640 px.
Since AstroPaper v1.4.0, OG images are generated automatically if not specified. Check out the announcement.