DocUp
DocUp is a lightweight personal blog and knowledge base built with Next.js, React, and Notion. It pulls public posts from a Notion database or data source, renders them in a clean feed, supports searching and filtering by tags and categories, and includes a small AI assistant powered by OpenRouter.
- Notion-powered content source
- Searchable blog feed
- Tag filtering with
/ - Category filtering with
# - Individual post pages with rich Notion block rendering
- Dark mode support
- AI chat assistant for filtering and content discovery
DocUp is designed to be easy to fork and adapt. If you want to run your own version, follow these steps:
- Fork or clone this repository.
- Duplicate this Template.
- Install dependencies with
npm install. - Create a Notion database.
- Create a
.envfile with your Notion token and database ID. - Optionally add an OpenRouter API key if you want the AI assistant enabled.
- Run
npm run devand start publishing posts.
You can use this as either:
- a personal blog
- a notes site
- a public writing archive
- a starter project for a Notion + Next.js app
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS
- Notion API
- OpenRouter API for chat
- Install dependencies:
npm install- Create a
.envfile in the project root:
NOTION_TOKEN=your_notion_integration_token
NOTION_DATABASE_ID=your_notion_database_or_data_source_id
OPENROUTER_API_KEY=your_openrouter_key
OPENROUTER_MODEL=openrouter/auto- Start the development server:
npm run dev- Open http://localhost:3000 in your browser.
NOTION_TOKEN: your Notion integration tokenNOTION_DATABASE_ID: the database ID (or data source ID) used by the app
OPENROUTER_API_KEY: enables the AI assistant in the UIOPENROUTER_MODEL: overrides the default model, defaults toopenrouter/auto
The app expects your Notion database to include properties that map to the fields used by the app:
TitleorName: post titleSlug: URL slug for the postSummary: short description shown on the feed/post pageType: optional post typeStatus: optional status; onlyPublicentries are shownDate: optional publish dateThumbnail: optional cover imageTags: multi-select tagsCategory: select field for category
You can duplicate this structure in Notion and use it as the content source for DocUp.
If you don't want to duplicate the template, you can still use your own Notion database as long as it has the same properties and naming.
Create a database with these properties:
Title(title property)Slug(text)Summary(text or rich text)Type(select, optional; set toPostif you want)Status(select, optional; usePublicfor live posts)Date(date)Thumbnail(files & media)Tags(multi-select)Category(select)
Title: Why I switched to a custom blog
Slug: why-i-switched-to-a-custom-blog
Summary: Notes on shipping a minimal writing workflow with Notion.
Type: Post
Status: Public
Date: 2026-09-15
Thumbnail: optional cover image
Tags: [nextjs, writing]
Category: essays- In Notion, create an internal integration or use an existing one.
- Share the database with that integration.
- Copy the database ID.
- Put it in
NOTION_DATABASE_IDin.env.
- Keep
Slugunique for each post. - Use
Status = Publiconly for posts you want visible in the feed. - Use
Status = Privateor leave it blank for drafts, notes, or unpublished content. - Use
CategoryandTagsconsistently so filtering feels useful. - Put the content of each post in the page body; the app will render the Notion blocks automatically.
- Use
Thumbnailfor a hero image if you want one on the post page.
DocUp treats posts as public when Status is exactly Public.
Public: appears in the homepage feed and can be opened directlyPrivate: hidden from the feed and not shown publicly- blank / unset: also hidden from the public feed
This makes it easy to keep draft posts, ideas, or private notes in the same Notion database without exposing them on the site.
The home page loads posts from Notion and renders them in a feed. The search input supports:
- plain text search across titles and summaries
- tag filtering using
/, for example/nextjs - category filtering using
#, for example#essays
Each post has its own route at /[slug], where the app fetches the page and renders the Notion block content.
The assistant is available from the top bar. If OPENROUTER_API_KEY is missing, the app falls back to lightweight built-in guidance about using tags and categories instead of failing outright.
app/
api/chat/route.ts
[slug]/page.tsx
components/
lib/
feed.ts
notion.ts
types.ts