Skip to content
0xxiao
Go back

Adding new posts in AstroPaper theme

Updated:

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

Free Classic wooden desk with writing materials, vintage clock, and a leather bag. Stock Photo

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:

PropertyDescriptionRemark
titleTitle of the post. (h1)required*
descriptionDescription of the post. Used in post excerpt and site description of the post.required*
pubDatetimePublished datetime in ISO 8601 format.required*
modDatetimeModified datetime in ISO 8601 format. (only add this property when a blog post is modified)optional
authorAuthor of the post.default = site.author
featuredWhether or not to display this post in the featured section of the home page.default = false
draftMark this post as ‘unpublished’.default = false
tagsRelated keywords for this post. Written in array YAML format.default = others
ogImageOG 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
canonicalURLCanonical URL (absolute), in case the article already exists on another source.default = Astro.site + Astro.url.pathname
hideEditPostHide the edit-post button under the post title. Applies only to the current post.default = false
timezoneSpecify 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:

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.

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.

![something](@/assets/images/example.jpg)

<!-- OR -->

![something](../../assets/images/example.jpg)

<!-- 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/assets is 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.

![something](/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.


Share this post:

Previous Post
Customizing AstroPaper theme color schemes
Next Post
Predefined color schemes