AI agents for SMEs - now running in production. See how the pilot works →

Why we did not build a CRM on WordPress post meta

WordPress makes it very easy to store anything. Register a post type, attach post meta, and you have a CRM by Friday. It demos well. It is also the reason a lot of WordPress business applications become unusable at exactly the point the business starts succeeding.

The shape of the problem

Post meta is a key-value table. One row per field per record. A contact with twenty fields is twenty rows, and querying contacts by two fields at once means joining that table to itself.

Filter on four fields and sort by a fifth and you are joining a single large table five times, with no useful composite index available because the values are all stored in one text column. The query planner cannot help you. Performance does not degrade gently – it falls off a cliff once the table stops fitting in memory.

Where the wall is

It depends on field count and query complexity, so any specific number is misleading. The honest version: a few thousand records with simple lookups is fine. Tens of thousands with multi-field reporting is where teams start describing the system as “slow”, and by then the data model is load-bearing across the application.

The trap is that nothing warns you. There is no error. Reports just take longer each month until someone stops running them.

What we did instead

For CCroute CRM we designed purpose-built tables with a dedicated prefix – one table per entity, real columns, real indexes, real foreign keys. Ten functional modules across nine tables.

WordPress kept the jobs it is genuinely excellent at: authentication, roles and capabilities, the admin interface, media handling, and content. The business data sat in a schema designed for how it would actually be queried.

The practical consequences:

  • Reporting queries stay predictable as the dataset grows, because they use indexes rather than repeated self-joins.
  • Constraints enforce integrity in the database, so an orphaned record is impossible rather than merely unlikely.
  • The schema is legible. The next developer can read the table structure and understand the domain.

When post meta is the right answer

For genuinely content-adjacent data – a subtitle, a layout flag, a featured toggle – post meta is exactly right and building tables for it is over-engineering. The distinction that matters is whether you will ever need to query across the data rather than just read it back for one record. Filtering, sorting and aggregating are the signals that you need columns.

Deciding this on day one costs nothing. Migrating a live CRM off post meta costs more than building it properly did.

Leave a comment

Your email address will not be published. Required fields are marked *

Book a consultation