In our fast-paced world, finding a quiet space for reflection is more important than ever. A "digital garden" is a unique approach to personal knowledge management—it's less of a chronological blog and more of a living, evolving space for your thoughts, learnings, and reflections. Unlike a traditional blog, a digital garden is a perpetual work in progress, allowing for interconnected ideas to grow over time.
This tutorial will guide you through building a digital garden specifically for your mental health notes using Next.js and MDX. We'll create a private, serene online space where you can document your journey, connect your thoughts, and cultivate a deeper understanding of yourself.
Prerequisites:
- Basic understanding of React and JavaScript.
- Node.js and npm (or yarn) installed on your machine.
- A code editor like VS Code.
Understanding the Problem: Beyond Traditional Note-Taking
Standard note-taking apps can be rigid and linear. For mental health, our thoughts are often interconnected and don't fit neatly into a timeline. A digital garden approach, with its emphasis on non-linear connections and personal growth, offers a more intuitive way to manage this kind of personal information.
By using Next.js, we get a powerful and fast framework for building our garden. MDX (Markdown with JSX) is the real game-changer here, allowing us to embed interactive React components directly into our notes for a richer, more dynamic experience.
Prerequisites: Setting Up Your Digital Greenhouse
First, let's get our project set up. Open your terminal and run:
npx create-next-app@latest mental-health-garden
Follow the prompts, choosing TypeScript and Tailwind CSS for this project.
Once the installation is complete, navigate into your new project directory:
cd mental-health-garden
Next, we'll install the necessary packages to work with MDX:
npm install @next/mdx @mdx-js/loader @mdx-js/react gray-matter
Now, let's configure Next.js to recognize MDX files. Create a next.config.mjs file in your project's root and add the following:
// next.config.mjs
import createMDX from '@next/mdx'
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
}
const withMDX = createMDX({
// Add markdown plugins here, as desired
})
export default withMDX(nextConfig)
This tells Next.js to treat .mdx files as pages.
Step 1: Planting Your First Seeds (Creating MDX Notes)
What we're doing
We'll create a directory to store our mental health notes as MDX files. Each file will contain some content and "frontmatter" (metadata like title, date, and tags).
Implementation
- Create a
notesdirectory at the root of your project. - Inside the
notesdirectory, create your first note, for example:first-reflection.mdx. - Add the following content to
first-reflection.mdx:
---
title: 'My First Reflection'
date: '2025-12-18'
tags: ['mindfulness', 'beginnings']
---
# Embracing the Journey
This is the first entry in my digital garden. It's a space for me to plant my thoughts and watch them grow.
Today, I'm focusing on the idea of **mindfulness**. It's about being present in the moment without judgment.
I find that when I'm mindful, my anxiety tends to decrease. It's a powerful tool.
How it works
The section between the --- is the frontmatter. We'll use a library called gray-matter to parse this data. The rest of the file is standard Markdown with the potential for JSX components.
Step 2: Displaying Your Notes
What we're doing
We'll create a dynamic route in Next.js to render our MDX notes. This means that any file we add to the notes directory will automatically become a page in our digital garden.
Implementation
- In your
appdirectory, create a new folder structure:notes/[slug]. - Inside
notes/[slug], create apage.tsxfile. This will be our template for displaying each note.
// app/notes/[slug]/page.tsx
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { MDXRemote } from 'next-mdx-remote/rsc';
import { notFound } from 'next/navigation';
const notesDirectory = path.join(process.cwd(), 'notes');
export async function generateStaticParams() {
const files = fs.readdirSync(notesDirectory);
return files.map((filename) => ({
slug: filename.replace('.mdx', ''),
}));
}
export default async function NotePage({ params }: { params: { slug: string } }) {
const { slug } = params;
const filePath = path.join(notesDirectory, `${slug}.mdx`);
if (!fs.existsSync(filePath)) {
return notFound();
}
const source = fs.readFileSync(filePath, 'utf8');
const { content, data } = matter(source);
return (
<article className="prose lg:prose-xl mx-auto p-4">
<h1>{data.title}</h1>
<p className="text-sm text-gray-500">
{new Date(data.date).toLocaleDateString()}
</p>
<div className="mt-4">
<MDXRemote source={content} />
</div>
</article>
);
}
How it works
generateStaticParamstells Next.js to pre-render a page for each of our notes.- The
NotePagecomponent reads the corresponding.mdxfile, parses the frontmatter and content usinggray-matter, and then renders the content usingMDXRemote.
Step 3: Creating a Mindful UI with Custom Components
What we're doing
A mental health garden should feel calm and personal. We'll use Tailwind CSS to create a clean, minimalist design and build a custom React component to embed in our MDX files for highlighting key insights.
Implementation
- Styling: In your
app/globals.css, you can define a soothing color palette and typography. - Custom Component: Create a
componentsdirectory in your project root. Inside, create a file namedInsight.tsx:
// components/Insight.tsx
import React from 'react';
const Insight = ({ children }: { children: React.ReactNode }) => {
return (
<div className="bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4 my-4 rounded">
<p className="font-bold">Insight ✨</p>
{children}
</div>
);
};
export default Insight;
- To use this component in your MDX files, create an
mdx-components.tsxfile in the root of your project:
// mdx-components.tsx
import type { MDXComponents } from 'mdx/types';
import Insight from './components/Insight';
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
Insight,
...components,
};
}
Note: This file is crucial for making your components available to MDX in the App Router.
- Now, you can use the
<Insight>component in your.mdxfiles:
---
title: 'Mindful Moments'
date: '2025-12-19'
tags: ['mindfulness', 'anxiety']
---
# Finding Calm in the Chaos
<Insight>
When I feel overwhelmed, taking just five deep breaths can make a world of difference.
</Insight>
Step 4: Interlinking Your Thoughts
What we're doing
A key feature of a digital garden is the ability to connect related ideas. We'll use Next.js's Link component to create these connections within our notes.
Implementation
- Update your
mdx-components.tsxfile to override the defaultatag with Next.js'sLinkcomponent for internal links.
// mdx-components.tsx
import type { MDXComponents } from 'mdx/types';
import Insight from './components/Insight';
import Link from 'next/link';
import { useMemo } from 'react';
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
Insight,
a: (props) => {
const href = props.href as string;
if (href.startsWith('/')) {
return <Link href={href} {...props} />;
}
return <a {...props} />;
},
...components,
};
}
- Now you can link between your notes using standard Markdown syntax:
This thought connects back to my [[first-reflection]].
[first-reflection]: /notes/first-reflection
Step 5: Implementing a Simple Search
What we're doing
To make your garden navigable as it grows, we'll add a simple search functionality. We'll create an API route that returns notes matching a search query.
Implementation
- Create an API route at
app/api/search/route.ts:
// app/api/search/route.ts
import { NextResponse } from 'next/server';
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
const notesDirectory = path.join(process.cwd(), 'notes');
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const query = searchParams.get('q');
if (!query) {
return NextResponse.json({ error: 'Query parameter is required' }, { status: 400 });
}
const files = fs.readdirSync(notesDirectory);
const results = files
.map((filename) => {
const filePath = path.join(notesDirectory, filename);
const fileContents = fs.readFileSync(filePath, 'utf8');
const { data, content } = matter(fileContents);
if (
data.title.toLowerCase().includes(query.toLowerCase()) ||
content.toLowerCase().includes(query.toLowerCase())
) {
return {
slug: filename.replace('.mdx', ''),
title: data.title,
};
}
return null;
})
.filter(Boolean);
return NextResponse.json(results);
}
- Create a search component in
components/Search.tsxto use this API route.
For a more robust search experience in a larger garden, consider using a library like fuse.js.
Conclusion
You've now built the foundation for a beautiful and functional digital garden for your mental health journey. This is a living project—a space for you to cultivate your thoughts, understand your emotions, and grow.
Next Steps:
- Tagging System: Create pages that list all notes with a specific tag.
- Visual Graph: Explore libraries like D3.js or React Flow to create a visual representation of how your notes are connected.
- Personalization: Continue to customize the styling to create a space that feels truly yours.