Core concepts
How Better Blog is structured and key APIs
Package structure
better-blog
: shared utilities, schemas, types and queriesbetter-blog/client
: client components (BlogRouterPage
,BetterBlogContextProvider
, hooks)better-blog/server
: server adapters (e.g.createServerAdapter
for SSR/SSG)better-blog/server/api
: API router utilities (e.g.createBlogApiRouter
)
Data provider
You inject a BlogDataProvider
implementation (CMS, files, API, DB):
export interface BlogDataProvider {
getAllPosts: (filter?: {
slug?: string
tag?: string
offset?: number
limit?: number
query?: string
published?: boolean
locale?: string
}) => Promise<Post[]>
getPostBySlug?: (slug: string, options?: { locale?: string }) => Promise<Post | null>
createPost?: (input: PostCreateExtendedInput) => Promise<Post>
updatePost?: (slug: string, input: PostUpdateExtendedInput) => Promise<Post>
deletePost?: (slug: string) => Promise<void>
}
API surface (most used)
- Utilities, Schemas, Types and Queries (
better-blog
)- shared routing utilities,
- zod schemas
- types
- low level tanstack query functions
- Server adapter (
better-blog/server
)createServerAdapter(serverConfig: BlogDataProvider, queryClient: QueryClient)
→{ generateStaticParams, generateMetadata, Entry }
createBlogApiRouter(serverConfig: BlogDataProvider, queryClient: QueryClient)
→{ router }
- Client (
better-blog/client
)BetterBlogContextProvider
- Hooks:
usePosts
,useCreatePost
, etc... - Client components:
BlogRouterPage
etc...
Architecture (high-level)
- Schema-driven routes and data; minimal state in components
- Strict client/server separation via dedicated entry points
TanStack Query
Why we use it:
- Caching + de/rehydration: Server prefetch + client hydration for SEO and zero-flash data
- Great DX: Automatic refetching, pagination support, and easy overrides