Skip to content

Authoring in Obsidian

The site content lives in src/content/docs/, which is also opened in Obsidian via the Vault CMS workflow. Everything here keeps that workflow non-fragile — no imports required, no JSX unless you want it.

Pick per note

  • .md — plain Markdown. Perfect for Obsidian. Cannot use <Aside>, <Tabs>, <Card> JSX directly, but you can use the directive syntax (:::note) which renders the same asides.
  • .mdx — Markdown + JSX. Everything on the site’s markdown-showcase page is available. Obsidian shows the import lines as raw text — ignore them, editing body text still works.

Copy this into a new note in Obsidian, save with a .md extension, and it will build without any JSX or imports.

my-new-post.md
---
title: My New Post
description: One-line summary that shows in search and previews.
tags: [kubernetes, notes]
# Optional — flip on for time-sensitive posts:
# date: 2026-07-30
# showDate: true
# draft: true # keep drafts out of Recent Posts
---
Intro paragraph. Regular Markdown works exactly as Obsidian previews it.
## Section heading
- Bullet
- **Bold**, *italic*, `inline code`, [links](https://example.com)
- Task lists: - [ ] not done · - [x] done
## Asides (Starlight extension)
Use the **directive syntax** — plain Markdown, no imports needed:
:::note[Optional title]
This renders as a note callout on the site. Obsidian shows it as text — that's fine.
:::
:::tip
Actionable advice.
:::
:::caution
Watch out for this.
:::
:::danger
Don't do this.
:::
## Code
```bash
kubectl get pods -A
```
Code with a title:
```yaml title="deployment.yaml"
apiVersion: apps/v1
kind: Deployment
```
## Images
Put images beside the note or in `src/assets/…`. Plain Markdown syntax works — Astro optimizes them:
![Description](./assets/diagram.png)
## Diagrams
```mermaid
flowchart LR
A[Idea] --> B[Draft] --> C[Publish]
```

Every field except title is optional. The schema (see frontmatter reference) is deliberately permissive:

  • src/content.config.ts
content.config.ts
extend: z.object({
date: z.coerce.date().optional(),
pubDate: z.coerce.date().optional(),
draft: z.boolean().optional(),
tags: z.array(z.string()).optional(),
showDate: z.boolean().optional(),
}),

So a note with just a title builds fine:

minimum-viable-note.md
---
title: A short thought
---
Body.

Rename to .mdx and import at the top:

rich-post.mdx
---
title: A rich post
---
import { Card, Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs>
<TabItem label="One">Content A</TabItem>
<TabItem label="Two">Content B</TabItem>
</Tabs>

Obsidian will show the import line as text. Ignore it — the file still saves and syncs cleanly.

  • Frontmatter has at least a title.
  • File is inside src/content/docs/… (not _bases/ or public/).
  • Extension matches contents: .md for plain markdown, .mdx for JSX.
  • Images live in src/assets/… (Astro optimizes) or a co-located folder.
  • If time-sensitive, set date: and showDate: true.
  • pnpm build locally — Vercel runs the same command in CI.