WordPress stores blog posts, pages, custom post types, and revisions in a single table: wp_posts. Metadata goes in wp_postmeta, a key-value store that requires JOINs for every query. This architecture is flexible and works well for content management. It does not work well for forums.
When bbPress stores forums, topics, and replies as custom post types in wp_posts, it inherits all the performance characteristics of that table, including the bad ones. Understanding why this matters will help you make better decisions about which forum plugin to use.
The Problem with wp_posts for Forums
Table Bloat
A WordPress site with 1,000 blog posts has roughly 1,000 rows in wp_posts (plus revisions). A forum with 10,000 topics and 30,000 replies adds 40,000 rows to the same table. Now your blog queries and forum queries are scanning the same massive table. Every query must filter by post_type to find the right records.
At 100,000+ forum records, wp_posts becomes a bottleneck for the entire site, not just the forum.
The wp_postmeta JOIN Problem
wp_postmeta is a key-value store. To get a topic’s vote count, reply count, view count, and author reputation in a single query, you need four separate JOINs to wp_postmeta. Each JOIN adds complexity and execution time.
A single topic page in bbPress can require 15–25 database queries because of this meta-query pattern. Most of those queries are JOINs against wp_postmeta to retrieve individual metadata values.
No Proper Indexes
wp_posts is indexed for blog content workflows (date-based sorting, author lookups, status filtering). It is not indexed for forum workflows (space-based filtering, vote sorting, reply counting, last-activity ordering). Every forum-specific query pattern fights the existing index structure.
How Custom Tables Solve This
Jetonomy uses 24 purpose-built MySQL tables. Each table is designed for a specific data type with proper indexes for the queries that actually run.
Dedicated Tables
| Data | wp_posts Approach | Custom Table Approach |
|---|---|---|
| Topics | Rows in wp_posts (post_type: topic) | Dedicated jt_posts table |
| Replies | Rows in wp_posts (post_type: reply) | Dedicated jt_replies table |
| Votes | Rows in wp_postmeta | Dedicated jt_votes table |
| Spaces | Rows in wp_posts (post_type: forum) | Dedicated jt_spaces table |
| User profiles | Rows in wp_usermeta | Dedicated jt_user_profiles table |
| Notifications | Custom option/meta storage | Dedicated jt_notifications table |
Denormalized Counters
Instead of counting replies with SELECT COUNT(*) FROM wp_posts WHERE post_parent = X on every page load, Jetonomy stores the reply count directly on the topic record. When a reply is created, the counter is incremented. When a reply is deleted, it is decremented.
This means displaying a topic list with reply counts requires zero COUNT queries. The data is already there, precomputed on every write. Same for vote scores, member counts, and last-activity timestamps.
Proper Indexes
Each table has indexes designed for the queries that actually run:
jt_posts: Indexed by space_id + last_reply_at (for topic listing by recent activity)jt_replies: Indexed by post_id + created_at (for chronological reply display)jt_votes: Indexed by votable_type + votable_id + user_id (for fast vote lookups)- FULLTEXT indexes on title, content, and content_plain columns for search
Performance Comparison
We benchmarked both approaches on identical hardware (2 CPU, 4GB RAM, MySQL 8.0, Redis object cache) with 25,000 topics and 75,000 replies:
| Operation | wp_posts (bbPress) | Custom Tables (Jetonomy) | Improvement |
|---|---|---|---|
| Topic listing (50 per page) | 2.4 seconds | 0.4 seconds | 6x faster |
| Single topic with 20 replies | 1.6 seconds | 0.3 seconds | 5x faster |
| Full-text search | 3.2 seconds | 0.5 seconds | 6x faster |
| User profile (posts + replies) | 1.2 seconds | 0.2 seconds | 6x faster |
| Database queries per page | 22 | 4 | 5.5x fewer |
The gap widens with scale. At 100,000+ topics, the wp_posts approach becomes nearly unusable without aggressive caching, while custom tables maintain consistent query times. For the full comparison, see our three-way plugin benchmark.
Cursor-Based Pagination
Most WordPress plugins use offset-based pagination: LIMIT 50 OFFSET 500. This requires MySQL to scan and discard 500 rows before returning 50. At page 100, it scans and discards 5,000 rows. Performance degrades linearly with page depth.
Jetonomy uses cursor-based pagination: WHERE last_reply_at < :cursor LIMIT 50. This uses the index directly regardless of how deep you paginate. Page 1 and page 100 perform identically.
The Trade-Off: WordPress Ecosystem Compatibility
Custom tables have one disadvantage: they do not work with WordPress functions that expect wp_posts data. WP_Query, get_posts(), and plugins that hook into post queries do not see custom table data.
Jetonomy handles this by providing its own model layer, REST API (42+ endpoints), and template system. Everything that needs to interact with forum data goes through Jetonomy's API, not through WordPress post functions.
For developers building integrations, this means using Jetonomy's REST API or model classes rather than WP_Query. For end users, it means the forum just works faster. The implementation detail is invisible.
Should You Care About This?
If your forum will stay under 5,000 topics, the architecture difference is negligible. Both approaches work fine at small scale.
If you expect to grow beyond 10,000 topics, and most active communities do within 1–2 years, the architecture matters enormously. Migrating from a wp_posts-based forum to a custom-table forum after hitting performance walls is possible (see our bbPress migration guide) but it is work you can avoid by choosing the right architecture from the start.
Getting Started
Jetonomy uses custom tables by default. No configuration needed. Install the plugin (setup guide), and the 24 tables are created automatically on activation. Your forum runs on an architecture designed for forum workloads from day one.
Implementation details that make the rollout smoother
Why Custom Database Tables Beat wp_posts for Forum Performance fits into the broader forums category through launch plans, migration steps, and setup choices. That matters because the technical setup is only one part of success. The way you structure spaces, roles, onboarding, and follow-up is what determines whether the forum becomes a searchable asset or just another neglected section of the site.
- Start with one public space and one private operator space so you can test permissions before the wider launch.
- Seed the first discussions yourself using the exact questions customers already ask in email, pre-sales chat, or onboarding calls.
- Define who can create spaces, who can moderate them, and what counts as an accepted answer before the first wave of members arrives.
Why teams evaluating this setup should look at Jetonomy Pro
Jetonomy Pro is useful here because it gives you Q&A, discussion spaces, trust levels, private areas, and a cleaner launch path than stitching together older forum plugins. If you want to know more and try Jetonomy, take a closer look at Jetonomy Pro. It is the most direct next step for teams that want to move from theory to an actual working WordPress community experience.
For articles like this one, the practical question is not only whether the approach works in theory. It is whether your chosen forum stack gives you the moderation depth, user experience, and extensibility to keep the system useful six months after launch. That is where a more complete product decision starts to matter.