Next.js App Router Blog MVP Design
A practical guide to designing an App Router-based blog MVP from a Clean Architecture perspective and organizing layer responsibilities and infrastructure trade-offs
Introduction
The goal of a blog MVP is to launch quickly, but if the initial structure is incorrect, content processing, SEO, and distribution stability will collapse as functions increase. App Router is advantageous for server component-oriented development, but it is also a structure that makes it easy for business logic to be concentrated in the route file.
This article covers how to design an App Router-based MVP with Clean Architecture Layer Separation to simultaneously secure release speed and scalability.
Problem definition
Problems that frequently arise in early MVPs are as follows:
app/**Data access/verification/processing logic is mixed in the route file.- SEO metadata creation rules are distributed across pages
- Content parsing failures are only revealed at runtime
- The deployment pipeline passed, but the actual page data was incomplete.
The key is to separate “routing” from “use cases” and keep the content model in a single path.
Concept explanation
Minimum layers required for MVP
| layer | responsibility | File example |
|---|---|---|
| Presentation | route/page configuration, request/response binding | app/posts/[slug]/page.tsx |
| Application | Use cases, sort/filter policies | lib/application/get-post-list.ts |
| Domain | Post Model, Tag Rules, Date Policy | lib/domain/post.ts |
| Infrastructure | File reading, MDX parsing, distribution integration | lib/posts.ts |
MVP feature scope
- Content:
content/posts/*.mdx - Route:
/,/posts,/posts/[slug],/tags,/about - SEO:
generateMetadata+ sitemap + rss - Verification: Check build step frontmatter
Code example
Example 1: Calling a use case from Route Handler
import { getPostListUseCase } from "@/lib/application/get-post-list";
export default async function PostsPage() {
const posts = await getPostListUseCase({
sortBy: "date_desc",
limit: 20,
});
return <PostList posts={posts} />;
}
Example 2: Fixing boundaries in the Application layer
import { postRepository } from "@/lib/infrastructure/post-repository";
type Params = {
sortBy: "date_desc" | "date_asc";
limit: number;
};
export async function getPostListUseCase(params: Params) {
const items = await postRepository.findAll();
const sorted = [...items].sort((a, b) =>
params.sortBy === "date_desc"
? new Date(b.date).getTime() - new Date(a.date).getTime()
: new Date(a.date).getTime() - new Date(b.date).getTime(),
);
return sorted.slice(0, params.limit);
}
Architecture Description
In App Router MVP, request flow and content flow must be viewed separately.
Clean Architecture layer structure
To create a maintainable MVP in practice, the boundaries below must be clearly maintained.
- Presentation: Routing, user input binding, page-by-page combination
- Application: Use case orchestration, sorting/filtering policy
- Domain: Core rules (tag/date/slug policy), type invariance
- Infrastructure: File system access, MDX parsing, external platform integration
Infrastructure diagram
Trade-off analysis
| Select | Advantages | Disadvantages | Recommended Situation |
|---|---|---|---|
| Route-centric, single implementation | Rapid initial development | Mixed responsibilities, difficult to test | Short Demo |
| Clean Architecture Separation | Highly resistant to change, easy to test | Initial rescue cost increases | MVP scheduled for operation |
| Maximize static creation | Performance/cost advantage | Real-time limitations | Content-centered service |
| Dynamic Rendering Blending | Real-time reflection glass | Cache/cost management required | Frequent data fluctuations |
“Too much abstraction” is a risk at the MVP stage, but starting without boundaries also increases the cost of scaling. The most practical method is to define the minimum layer first and expand only when necessary.
Cleanup
The core of App Router Blog MVP is boundary design rather than a list of features. If you fix the three things below first, adding features later will be much safer.
- Routes are only responsible for combination, and use cases are placed in a separate layer.
- The content model is managed through a single verification path.
- Metadata/sitemap/rss creation uses the same data source.
If this principle is followed, the structure will not be easily shaken even if search, tag, analysis, and recommendation functions are added after MVP.