Personal site built with Next.js App Router, MDX-based writing, and a small JSON feed.
- Next.js
16 - React
19 - TypeScript (strict mode)
- Tailwind CSS
4 - MDX via
@next/mdx+next-mdx-remote shiki+rehype-pretty-code— syntax highlighting with language-aware grammarspnpm(locked viapackageManagerinpackage.json)
pnpm install
pnpm devApp runs on http://localhost:3000.
Production:
pnpm build
pnpm startCreate a .env file at the project root (never commit it — it's in .gitignore):
# Canonical base URL used in sitemap, robots.txt, structured data, and OG images.
# Defaults to https://larsniet.com when unset.
NEXT_PUBLIC_BASE_URL=https://your-domain.com
# DEV.to API key for cross-posting. Generate at dev.to/settings/extensions.
DEVTO_API_KEY=your_api_key_hereapp/page.tsx— homepageapp/journey/page.tsx— list of journey postsapp/journey/[slug]/page.tsx— individual MDX post route (static params + revalidate)app/journey/posts/*.mdx— post contentapp/journey/utils.ts— post loading, MDX compile, date formattingapp/components/mdx-remote-components.tsx— MDX render componentsapp/sitemap.ts,app/robots.ts,app/og/route.tsx— SEO/metadata routesapp/manifest.ts+ServiceWorkerRegister— PWA basicsscripts/— automation scripts (see below).github/workflows/— GitHub Actions
Add a new file in app/journey/posts/ with .mdx extension and frontmatter:
---
title: Your Post Title
publishedAt: 2026-02-19
summary: Short summary for list view and meta description.
image: /images/your-image.jpg # optional OG image
featured: true # optional
---Posts are read from the filesystem, compiled to React, sorted by publishedAt, and rendered at /journey/[slug].
When you push a new .mdx file to main, the GitHub Actions workflow (.github/workflows/crosspost-devto.yml) automatically cross-posts it to DEV.to with canonical_url pointing back to this site, so all SEO value stays here.
Publishes every post in app/journey/posts/ to DEV.to. Safe to re-run — posts that already exist on DEV.to (matched by canonical URL) are skipped automatically.
DEVTO_API_KEY=your_key node scripts/crosspost-all.jsDEVTO_API_KEY=your_key BASE_URL=https://larsniet.com node scripts/crosspost-devto.js app/journey/posts/my-post.mdx- XML sitemap at
/sitemap.xml(all pages + posts) robots.txtat/robots.txt- Per-page
title,description, andcanonicalmetadata - Open Graph + Twitter card metadata on post pages
- Structured data (
WebSite+Person) on homepage,BreadcrumbListon all subpages,BlogPostingon posts
MIT. See LICENSE.