# How to build a blog in Bubble

- Tool: Bubble
- Difficulty: Beginner
- Time required: 25-30 min
- Compatibility: All Bubble plans
- Last updated: March 2026

## TL;DR

Building a blog in Bubble involves creating a Post Data Type with fields for title, body, author, and category, a rich text editor for writing, a dynamic blog post page, and an index page with a Repeating Group showing all posts. This tutorial covers the full system including SEO-friendly URLs, categories, and a basic CMS dashboard.

## Overview: Setting Up a Blog in Bubble

A blog is one of the most common features in web apps, and Bubble gives you everything you need to build one from scratch. Unlike WordPress where the blog structure is predefined, in Bubble you design every piece — the data structure, editor, listing page, and individual post pages. This gives you complete control over the design and functionality.

## Before you start

- A Bubble app where you want to add a blog
- Basic familiarity with Bubble Data Types and the Design tab
- Understanding of dynamic pages and page data types
- A rich text editor plugin installed (e.g., Rich Text Editor by ZeroqodeX)

## Step-by-step guide

### 1. Create the Post Data Type and related types

Go to the Data tab and create a new Data Type called Post. Add these fields: title (text), body (text — this will hold the rich text HTML), excerpt (text — a short summary for the listing page), featured_image (image), author (User), category (text or an Option Set), tags (text, list), published (yes/no, default: no), published_date (date), and slug (text — for SEO-friendly URLs). Optionally create a Category Option Set with entries like Technology, Business, Tutorial.

> Pro tip: Use an Option Set for categories instead of a text field — it is faster to query, consistent, and does not cost Workload Units for lookups.

**Expected result:** A Post Data Type with all necessary fields and optionally a Category Option Set.

### 2. Build the blog post editor page

Create a new page called blog-admin or post-editor. Add an Input element for the post title, a Rich Text Editor element (from the plugin you installed) for the body content, an Input for the excerpt, a File Uploader for the featured image, a Dropdown for the category (source: All Categories Option Set), and a multi-tag input or Repeating Group for tags. Add a Save as Draft button and a Publish button.

**Expected result:** An admin page with a full editor interface for creating and editing blog posts.

### 3. Set up the save and publish workflows

For the Save as Draft button workflow: Create a new Post with all field values, setting published to no. For the Publish button workflow: Create a new Post (or Make Changes if editing) with published set to yes and published_date set to Current date/time. Also set the slug using the Set a Thing's Slug action — use the title formatted as a URL-safe string. Add a condition to check that the title is not empty before allowing save.

> Pro tip: Use Set a Thing's Slug (not Make Changes) to set the slug — this is a separate action specific to the slug field.

**Expected result:** Authors can save posts as drafts or publish them immediately, with SEO-friendly slugs auto-generated.

### 4. Create the dynamic blog post page

Create a new page called blog-post. Set its Type of content to Post (in the page settings). This makes the page expect a Post record as its data source. Add elements to display the post: a Text element for the title (dynamic data: Current Page Post's title), an Image for the featured image, a Text element for the published date, a Text for the author name, and an HTML element for the body content (because the rich text editor outputs HTML). Set the HTML source to Current Page Post's body.

**Expected result:** A dynamic page that displays any blog post passed to it, with proper title, image, date, and body rendering.

### 5. Build the blog index page with a Repeating Group

Create a page called blog. Add a Repeating Group with Type of content set to Post and Data source set to Do a Search for Posts where published = yes, sorted by published_date descending. Inside each cell, add: the featured image, post title (as a clickable link), the excerpt, the category, and the published date. Make the title or a Read More link navigate to the blog-post page, sending the current cell's Post as the data.

> Pro tip: Add a Category filter dropdown above the Repeating Group and add category = Dropdown's value as a constraint with Ignore empty constraints checked.

**Expected result:** A blog listing page showing all published posts with images, titles, excerpts, and links to the full post.

### 6. Add SEO meta tags to the blog post page

On the blog-post page, go to the page settings and configure the SEO meta tags dynamically. Set the Page title to Current Page Post's title. Set the meta description to Current Page Post's excerpt. Set the OG image to Current Page Post's featured_image. These dynamic meta tags ensure each blog post has unique SEO metadata when shared on social media or indexed by search engines.

**Expected result:** Each blog post has unique meta tags for SEO and social sharing.

## Complete code example

File: `Workflow summary`

```text
BLOG SYSTEM SUMMARY
====================

DATA STRUCTURE:
  Post Data Type:
    - title (text)
    - body (text — rich text HTML)
    - excerpt (text — 150-200 chars)
    - featured_image (image)
    - author (User)
    - category (Category Option Set)
    - tags (text, list)
    - published (yes/no, default: no)
    - published_date (date)
    - slug (text — auto-set)

  Category Option Set:
    - Technology
    - Business
    - Tutorial
    - News

PAGES:
  1. blog-admin (post editor, admin only)
  2. blog (index/listing page)
  3. blog-post (dynamic individual post page, type: Post)

EDITOR WORKFLOWS:
  Save Draft button:
    Action: Create a new Post
      → title, body, excerpt, featured_image, author = Current User
      → published = no
    Action: Set a Thing's Slug on Result of Step 1
      → Slug: title (auto-formatted)

  Publish button:
    Action: Create a new Post (or Make Changes)
      → published = yes
      → published_date = Current date/time
    Action: Set a Thing's Slug

INDEX PAGE:
  RepeatingGroup:
    Type: Post
    Source: Search for Posts
      → published = yes
      → Sort: published_date descending
    Cell: image, title (link to blog-post), excerpt, category, date

DYNAMIC POST PAGE:
  Page type: Post
  Elements:
    - Text: Current Page Post's title (H1 style)
    - Image: Current Page Post's featured_image
    - Text: Current Page Post's published_date formatted as MMM D, YYYY
    - Text: Current Page Post's author's name
    - HTML: Current Page Post's body

SEO (blog-post page settings):
  Page title: Current Page Post's title
  Meta description: Current Page Post's excerpt
  OG image: Current Page Post's featured_image
```

## Common mistakes

- **Using a Text element to display rich text body content** — The rich text editor saves HTML markup. A Text element displays raw HTML tags instead of rendering them. Fix: Use an HTML element to display the body content — it renders the HTML markup correctly
- **Not setting the page type on the blog-post page** — Without a page type, you cannot access Current Page Post's fields in dynamic expressions Fix: In the blog-post page settings, set Type of content to Post before adding any dynamic elements
- **Forgetting to filter by published = yes on the index page** — Without this filter, draft posts are visible to all visitors on the blog listing page Fix: Add published = yes as a constraint on the Repeating Group's Do a Search for expression

## Best practices

- Use an Option Set for categories for better performance and consistency
- Set SEO meta tags dynamically on the blog post page using Current Page Post data
- Generate URL slugs from the post title using Set a Thing's Slug for SEO-friendly URLs
- Add an excerpt field for listing pages instead of truncating the full body text
- Restrict the blog editor page to admin users with Privacy Rules or page-level conditions
- Add pagination to the blog index Repeating Group (10-15 posts per page)
- Include a featured image on every post for better visual impact on the listing page and social shares

## Frequently asked questions

### Which rich text editor plugin should I use?

Popular options include the Rich Text Editor by ZeroqodeX, the TinyMCE plugin, and Quill-based editors. Choose one that supports image embedding, formatting, and outputs clean HTML.

### Can I schedule posts to publish in the future?

Yes. Add a scheduled_publish_date field to your Post. Create a backend workflow that checks for unpublished posts where scheduled_publish_date has passed, and sets published to yes. Schedule it to run every hour.

### How do I add comments to blog posts?

Create a Comment Data Type with fields for body (text), author (User), and post (Post). Add a comment form and Repeating Group on the blog-post page. Privacy Rules control who can comment.

### Will my blog posts be indexed by Google?

Yes, if you set up meta tags and a sitemap. Bubble renders content server-side for search engine crawlers, so your dynamic post pages are indexable.

### Can I let multiple authors write posts?

Yes. The author field on Post links to the User who created it. Add a role field to your User type and restrict the editor page to users with an author or admin role.

### How do I handle blog SEO beyond meta tags?

Add structured data, canonical URLs, and ensure fast page loads. For comprehensive blog SEO strategy in Bubble, RapidDev can help optimize your blog for search engine rankings and Core Web Vitals.

---

Source: https://www.rapidevelopers.com/bubble-tutorial/set-up-a-blog-in-bubble
© RapidDev — https://www.rapidevelopers.com/bubble-tutorial/set-up-a-blog-in-bubble
