A full-stack platform built with Turborepo to host React-based apps with Sanity CMS. This monorepo gives frontend developers a place to build small components, experiment with new technologies, and ship fully functional apps.
This repository uses a monorepo to:
- Share UI components and modules across apps
- Spin up focused apps (blog, docs, studio) without duplicating setup
- Share TypeScript types between Studio and Blog
- Reuse design tokens and Tailwind config
- Keep CMS schemas aligned with frontend components
- Simplify tooling, dependencies, and builds
- π Next.js 15 with App Router and React Server Components
- π¨ Tailwind CSS v4 with custom design tokens
- π¦ Turborepo for blazing-fast builds
- ποΈ Sanity CMS for structured content management
- π§© Modular Architecture with shared UI components
- π± Fully Responsive design system
- π― Type-Safe with TypeScript throughout
- π₯ Hot Module Replacement with Turbopack
- π ESLint & Prettier configured for code quality
blog-app/
βββ apps/
β βββ blog/
β β βββ src/
β β β βββ app/ # Next.js App Router
β β β βββ components/ # React components
β β β βββ sanity/ # Sanity client & queries
β β βββ package.json
β βββ docs/
β βββ studio/
β βββ schemaTypes/ # Sanity schema definitions
β β βββ documents/ # Document types
β β βββ objects/ # Object types
β β βββ modules/ # Module types
β βββ structure/ # Studio structure
βββ packages/
β βββ ui/
β β βββ src/
β β βββ components/ # Shared components
β β βββ lib/ # Utilities
β βββ modules/
β β βββ src/
β β βββ modules/ # Content modules
β βββ tailwind-config/
β βββ design-tokens.css # Global design tokens
βββ docs/ # Documentation
βββ package.json # Root package.json
βββ pnpm-workspace.yaml # Workspace configuration
βββ turbo.json # Turborepo configuration
This monorepo uses pnpm as a package manager and includes the following packages and apps:
apps/
βββ blog/ # Main Next.js blog application
βββ docs/ # Documentation site
βββ studio/ # Sanity Studio CMS
-
blog- The primary Next.js application featuring:- Dynamic routing with
[slug]pages - Sanity content integration
- Server-side rendering and ISR
- Rich text rendering
- Custom page builder
- Dynamic routing with
-
docs- The documentation app built with Next.js:- Project docs and implementation notes
- Shared UI package integration
- Lightweight environment for docs-focused iteration
-
studio- Sanity Studio for content management:- Custom schema types (posts, authors, categories, tags)
- Visual content editing
- Type generation for TypeScript
- Live preview integration
packages/
βββ ui/ # Shared React components
βββ modules/ # Content modules
βββ content-types/ # Sanity type definitions
βββ tailwind-config/ # Shared Tailwind configuration
βββ typescript-config/ # Shared TypeScript configs
βββ eslint-config/ # Shared ESLint configurations
-
@repo/ui- Reusable UI components with Tailwind CSS:- Button, Input, Card, etc.
- Built with
class-variance-authorityandradix-ui - Fully typed with TypeScript
-
@repo/modules- Content modules for page building:- Accordion, BlogList, ImageTeaser
- RichText, TeaserList components
- Modular content architecture
-
@repo/content-types- Generated Sanity types -
@repo/tailwind-config- Centralized Tailwind configuration -
@repo/typescript-config- Shared TypeScript configurations -
@repo/eslint-config- ESLint configurations for Next.js and React
- Node.js 18 or later
- pnpm 10.15.1 or later
- Clone the repository:
git clone https://github.com/bashirkarimi/blog-app.git
cd blog-app- Install dependencies:
pnpm install- Set up environment variables:
# Create local environment files
touch apps/blog/.env.local
touch apps/studio/.env.localFill in the following environment variables in each .env.local file:
NEXT_PUBLIC_SANITY_PROJECT_ID=<your_sanity_project_id>
NEXT_PUBLIC_SANITY_DATASET=<dataset_name>
SANITY_STUDIO_PROJECT_ID=<same_as_above>
SANITY_STUDIO_DATASET=<same_as_above>
SANITY_STUDIO_API_TOKEN=<token_with_required_permissions>
You can retrieve these values from the Sanity project dashboard under Project settings β API.
- Configure Sanity:
- Create a Sanity project at sanity.io
- Add your project ID and dataset to the environment files
Run all apps in development mode:
pnpm devThis will start:
- Blog app: http://localhost:3000
- Docs app: http://localhost:3001
- Studio: http://localhost:3333
Or run individual apps:
# Run only the blog
pnpm --filter blog dev
# Run only the studio
pnpm --filter @repo/studio dev
# Run only the docs site
pnpm --filter docs devBuild all apps and packages:
pnpm buildBuild specific app:
pnpm --filter blog buildThis project uses Tailwind CSS v4 with a custom design system:
- Design Tokens: Centralized in
packages/tailwind-config/design-tokens.css - Component Library: Built with Radix UI primitives
- Variants: Managed with
class-variance-authority - Dark Mode: Full dark mode support
- Data loading & preview: Server Components call
sanityFetch(seeapps/blog/src/sanity/live.ts) so every route benefits from ISR-friendly caching and Sanity Live Preview via<SanityLive />inlayout.jsx. If critical settings are missing, routes short-circuit tonotFound()to avoid partially rendered pages. - Composable page builder:
PageBuilderrenders heros and sections based on Sanity documents. It extends the shared@repo/modulesregistry with a localRichTextrenderer that handles Portable Text images, external link security attributes, and internal links for accessible content blocks. - Shared module registry:
apps/blog/src/components/section-renderer.tsxcomposes@repo/modules/section-renderer, so adding a new module inpackages/modulesimmediately makes it available to editorial teams. - Blog routing: Static post pages (
app/post/[slug]/page.tsx) opt intogenerateStaticParams()for SSG while still usingsanityFetchat runtime for fresh data. Landing pages under/[slug]reuse the same builder for marketing-style content without duplicating layout logic. - API surface:
GET /api/postsis a dynamic route that streams paginated posts from GROQ. It acceptslimit(1-50, default 6),offset,category, andmodequery params and responds with{ posts, total, offset, limit, hasMore, category }, making it easy to power infinite scroll or βload moreβ UIs without exposing Sanity directly.
| Command | Description |
|---|---|
pnpm --filter @repo/studio dev |
Run Sanity Studio locally with hot reloads |
pnpm --filter @repo/studio typegen |
Regenerate apps/blog/src/sanity/types.ts via sanity schema extract + sanity typegen generate |
pnpm --filter @repo/studio deploy |
Deploy the Studio to the managed Sanity hosting |
pnpm --filter @repo/studio deploy-graphql |
Publish the projectβs GraphQL API for external consumers |
| Command | Description |
|---|---|
pnpm dev |
Start all apps in development mode |
pnpm build |
Build all apps and packages |
pnpm lint |
Lint all packages |
pnpm check-types |
Type-check all packages |
pnpm format |
Format code with Prettier |
pnpm lintenforces the shared ESLint rules across apps and packages.pnpm check-typescatches TypeScript drift after schema or component updates.- Add Jest/Playwright coverage as the project grows and document new commands here for future contributors.
- Blog / Docs: Deploy to Vercel (or another Next.js-compatible host) and mirror the environment variables listed above.
- Sanity Studio: Deploy with
pnpm --filter @repo/studio deployand publish the GraphQL API viapnpm --filter @repo/studio deploy-graphqlwhen external systems need access. - Enable the Turborepo remote cache in CI/CD to speed up incremental builds.
- Next.js 15 β React framework with first-class Sanity integration and App Router conveniences for page-building workflows
- React 19 β UI library
- TypeScript β Type safety
- Tailwind CSS v4 β Utility-first styling with:
- Design token support
- Zero-configuration PostCSS pipeline
- Close interoperability with Radix primitives
- Strong DX during component development
- Sanity β Headless CMS that powers the page-builder architecture with:
- A fully customizable schema system
- Real-time collaborative editing
- Rich Portable Text content
- Type-safe code generation
- Live preview out of the box
- Fast GROQ querying tailored to dynamic blogs and landing pages
- next-sanity - Sanity integration
- @sanity/image-url - Image optimization
-
Turborepo - Monorepo build system
Chosen for its:
- Blazing-fast caching
- Monorepo-aware pipelines
- Zero-config task running
- Remote cache for CI/CD
- Perfect match for JS/TS ecosystem
-
pnpm - Package manager Selected due to:
- Fast and disk-efficient package management
- Strict dependency isolation
- Native workspace support
- Symlinked node_modules for improved DX
-
ESLint - Code linting
-
Prettier - Code formatting
- Radix UI - Headless UI primitives
- class-variance-authority - Variant management
- tailwind-merge - Utility merging
Check out the docs/ directory for additional documentation:
- Tailwind v4 Monorepo Setup
- More guides (architecture, content modeling, etc.) live alongside the code and will continue to grow with the project. If you add a feature, please co-locate its documentation under
docs/.