Personal Blog about programming, tech, Japan, gaming, green tea, and trying new things.
Built with Next.js, MDX, Tailwind CSS, and shadcn/ui.
Check it out »
This project is a personal blog to broaden my tech stack and learn new things. It will contain posts about programming, tech, Japan, gaming, green tea, and trying new things.
Another core part will be tutorial series about setting up an creating web applications with various frameworks and libraries.
- MDX Content: Blog posts written in MDX (
.mdx) allowing Markdown + React components. - Dynamic Routing: Posts accessible via
/posts/entry/[slug]. - Blog Index Page: Overview page at
/postswith:- Gallery view for posts with featured images.
- Client-side tag filtering.
- Posts sorted by date.
- Syntax Highlighting: Code blocks automatically highlighted using
rehype-pretty-codeandshiki. - Table of Contents: Auto-generated TOC for individual posts (headings).
- Theming: Light/Dark/System theme support using
next-themesandshadcn/uiCSS variables. - SEO:
- Dynamic generation of
robots.txtandsitemap.xml. - Dynamic page titles and descriptions.
- Canonical URLs, Open Graph, and Twitter Card meta tags for posts and pages.
- Dynamic generation of
- RSS Feed: Dynamically generated RSS feed available at
/rss.xml. - Draft Mode: Posts marked as
draft: truein frontmatter are only visible during local development (pnpm dev).
.
├── app/
│ ├── blog-posts/ # Location for all .mdx blog post files
│ ├── posts/
│ │ ├── entry/
│ │ │ └── [slug]/
│ │ │ └── page.tsx # Individual blog post page component
│ │ └── page.tsx # Blog index/overview page component
│ ├── robots.txt/
│ ├── rss.xml/
│ ├── sitemap.xml/
│ ├── layout.tsx
│ ├── page.tsx
│ └── globals.css
├── components/
├── lib/ # Utility functions and helpers
├── public/ # Static assets (images, fonts, etc.)- Location: Add new blog posts as
.mdxfiles inside theapp/blog-posts/directory. - Filename: Use lowercase, hyphenated filenames for posts (e.g.,
my-cool-new-post.mdx). This filename (without.mdx) becomes the URL slug. Avoid spaces or special characters as they will not be URL-friendly. - Format: Write content using Markdown and embed React components if needed (MDX).
- Frontmatter: Each post must include YAML frontmatter at the very top:
--- title: 'Awesome Post Title' date: 'YYYY-MM-DD' # e.g., 2025-04-04 description: 'A short, compelling summary of your post for previews and SEO.' draft: false # Set to true to hide from production builds (visible in dev) tags: ['tag1', 'coding', 'another-tag'] # Optional image: '/1_donut.jpg' --- Your main post content starts here...
- Node.js (v22 or later recommended)
- pnpm (You can install it via
npm install -g pnpm)
- Clone the repository:
git clone https://github.com/AndreasRoither/blog.git your-blog cd your-blog - Install dependencies using pnpm:
pnpm install
Start the development server:
pnpm dev- Open your browser and navigate to
http://localhost:3000to view the blog. Production build:
pnpm build:prodStart the production server:
pnpm startBuild the Docker image:
docker build -t andreasroither/blog .Run the container:
docker run -p 127.0.0.1:3000:3000 andreasroither/blogRun with enhanced security (recommended for production):
docker run \
--read-only \
--tmpfs /tmp:noexec,nosuid,size=64m \
--tmpfs /app/.next/cache:noexec,nosuid,size=128m \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--pids-limit=100 \
--memory=512m \
--cpus=1 \
-p 127.0.0.1:3000:3000 \
andreasroither/blogNote: The --tmpfs /app/.next/cache mount is only required when using --read-only. Without that flag, the cache directory is already writable in the image.
Runs the end-to-end tests.
pnpm exec playwright test [--ui,--debug]Starts the interactive UI mode.
pnpm exec playwright test --uiAuto generate tests with Codegen.
pnpm exec playwright codegen- Next.js (v14+ with App Router)
- React (v18+)
- TypeScript
- Tailwind CSS
- shadcn/ui (Component primitives via Radix UI)
- Playwright (End-to-end testing)
- MDX (via
next-mdx-remote) - next-themes (Theming)
- rehype-pretty-code & shiki (Syntax Highlighting)
- rehype-slug (Heading IDs for TOC)
- gray-matter (Frontmatter parsing)
- date-fns (Date formatting)
- rss (RSS feed generation)
- reading-time (Estimate post read time)
- pnpm (Package Manager)
- biome (Code formatter and linter)
- Seo for blog posts
- Individual robots.txt check from frontmatter for blog posts
- Tutorial series overview page / separate section?
- Do not regenerate sitemap if no new posts
- Do not regenerate rss feed if no new posts
- Do not regenerate robots.txt if no new posts
- Change series description to use
seriesDescriptionfrom frontmatter- also custom image for series instead of image of first post