• ShipSaaSDocumentation
  • Introduction
  • Getting Started
    • Installation
    • Environment Setup
    • Database Setup
    • Development Guide
  • Database
    • Repository Pattern
    • Drizzle Queries
    • Migration Workflow
    • Drizzle Studio
    • Best Practices
  • File Management
    • File Upload Component
    • Server Actions
    • Storage Configuration
  • Authentication Methods
    • Credentials Authentication
    • Magic Link Authentication
    • Two-Factor Authentication (2FA)
    • Social Authentication
    • API Keys & Bearer Tokens
    • Organizations (Multi-tenant)
  • Authorization & Permissions
    • Roles & Hierarchy
    • Route Protection
    • API Protection
    • CASL Permissions
  • Email & Notifications
    • Resend Setup
    • React Email Templates
    • Notification System
    • Email Workflows
    • Customization & Extension
  • Stripe & Payments
    • Stripe Setup
    • Better Auth Integration
    • Checkout Methods
    • Subscription Management
    • Admin Dashboard
    • Webhook Events
  • Architecture & Development
    • Presentation Layer
    • Service Layer
    • Persistence Layer
    • Helpers Architecture
    • Project Structure
    • Development Workflow
  • Testing
    • General Testing
    • Unit Testing
    • UI Component Testing
    • Repository Testing
    • Service Testing
    • End-to-End Testing
  • Deployment
    • Vercel Deployment
    • GitHub Actions CI/CD
    • Database Backup & Restore
    • Database Migrations
    • Troubleshooting Deployment
  • AI Agents Integration
  • Blog Management
    • Blog Setup
    • MDX Blog
    • Database Blog
  • Async Tasks
    • Setup
    • Email Workflows
    • Payment Processing
    • Maintenance Jobs
  1. Documentation
  2. Blog Management
  3. Blog Setup
Buydocschangelogsdemocommunity

Blog Setup

PreviousBlog ManagementNextMDX Blog
On this page
Enable Blog PagesDatabase SetupAdmin AccessNavigation SetupSEO ConfigurationInternationalizationDevelopment Workflow

Configure and enable the blog system in your SaaS boilerplate.

Enable Blog Pages

The blog system is controlled by environment configuration:

1

Environment Configuration

Add blog page configuration to your environment file:

bash
# .env.local or .env.production
ENABLE_BLOG=true

This enables both blog routes:

  • /blog - Database-driven blog
  • /blog/mdx - Static MDX blog
2

Verify Configuration

The boilerplate checks page enablement with:

typescript
// lib/utils.ts
import { PagesConst } from '@/env'

export function isPageEnabled(page: string): boolean {
  return process.env[`ENABLE_${page}`] === 'true'
}

// Usage in pages
if (!isPageEnabled(PagesConst.BLOG)) {
  return notFound()
}
3

Development Server

Start your development server to see the blog:

bash
pnpm dev

Available Routes:

  • http://localhost:3000/blog - Database blog list
  • http://localhost:3000/blog/mdx - MDX blog list
  • http://localhost:3000/admin/blog - Admin dashboard (requires login)

Database Setup

For the database blog system, ensure your database includes the blog schema:

1

Run Migrations

Apply database migrations to create blog tables:

bash
pnpm db:migrate

This creates the necessary tables:

  • post - Main post data
  • post_translation - Multi-language content
  • category - Content categories
  • hashtag - Content tags
  • post_hashtag - Tag associations
2

Seed Sample Data (Optional)

Add sample blog content for development:

bash
pnpm db:seed

This creates:

  • Sample categories
  • Sample hashtags
  • Sample blog posts with translations
  • Published and draft content examples
3

Verify Database

Check your database setup:

bash
pnpm db:studio

This opens Drizzle Studio where you can:

  • View blog tables
  • Check sample data
  • Manually add content
  • Test relationships

Admin Access

Configure admin access for content management:

1

User Permissions

Blog management requires specific role permissions:

typescript
// Blog permissions by role
const blogPermissions = {
  'blog-post:create': ['ADMIN', 'REDACTOR'],
  'blog-post:read': ['ADMIN', 'REDACTOR', 'MODERATOR'],
  'blog-post:update': ['ADMIN', 'REDACTOR'],
  'blog-post:delete': ['ADMIN'],
  'blog-post:publish': ['ADMIN', 'REDACTOR']
}

Required Roles:

  • ADMIN - Full blog management access
  • REDACTOR - Can create, edit, and publish posts
  • MODERATOR - Can view posts only
2

Access Admin Dashboard

  1. Login to your application
  2. Ensure Admin Role in your user profile
  3. Navigate to /admin/blog
  4. Create Content using the admin interface

If you don't see the blog admin, check your user role in the database or use Drizzle Studio to update your user permissions.

Navigation Setup

Add blog links to your application navigation:

tsx
// components/navigation.tsx
const navigation = [
  { name: 'Home', href: '/' },
  { name: 'Blog', href: '/blog' },
  { name: 'Documentation', href: '/blog/mdx' },
  // ... other links
]
tsx
// components/admin-navigation.tsx (for admin users)
const adminNavigation = [
  { name: 'Dashboard', href: '/admin' },
  { name: 'Blog Management', href: '/admin/blog' },
  // ... other admin links
]
tsx
// components/footer.tsx
const footerLinks = {
  resources: [
    { name: 'Blog', href: '/blog' },
    { name: 'Documentation', href: '/blog/mdx' },
    // ... other resource links
  ]
}

SEO Configuration

Configure SEO settings for blog pages:

1

Meta Tags Configuration

Blog pages automatically generate SEO meta tags:

typescript
// Automatic meta generation for blog posts
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPostBySlug(params.slug)

  return {
    title: post.title,
    description: post.description,
    openGraph: {
      title: post.title,
      description: post.description,
      type: 'article',
      publishedTime: post.publishedAt,
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.description,
    }
  }
}
2

Sitemap Generation

Blog posts are automatically included in your sitemap:

typescript
// Blog posts added to sitemap.xml
const blogPosts = await getAllPublishedPosts()
const blogUrls = blogPosts.map(post => ({
  url: `${baseUrl}/blog/${post.slug}`,
  lastModified: post.updatedAt,
  changeFrequency: 'weekly' as const,
  priority: 0.7,
}))

Internationalization

The blog system supports multiple languages:

1

Language Configuration

Configure supported languages in your i18n setup:

typescript
// i18n/routing.ts
export const routing = defineRouting({
  locales: ['en', 'fr', 'es'],
  defaultLocale: 'en'
})

// Supported languages for blog content
type SupportedLanguage = 'en' | 'fr' | 'es'
2

Content Translation

Blog posts automatically support multiple languages:

  • Database Blog: Each post can have translations in multiple languages
  • MDX Blog: Create separate MDX files for each language
  • Navigation: Language switcher works with blog content
  • SEO: Meta tags generated per language

Development Workflow

1

Local Development

bash
# Start development server
pnpm dev

# Check blog functionality
# Visit: http://localhost:3000/blog
# Visit: http://localhost:3000/admin/blog
2

Content Testing

bash
# Reset and seed database with sample content
pnpm db:reset-seed

# Open database studio to manage content
pnpm db:studio

# Check blog in browser
open http://localhost:3000/blog
3

Production Deployment

bash
# Build application
pnpm build

# Run production migrations
pnpm db:migrate

# Deploy to your hosting platform
# Blog will be available at yourdomain.com/blog

Blog Ready! Your blog system is now configured and ready for content creation. Visit /admin/blog to start creating content or add MDX files to start with static content.