October 29, 2022

Webflow CMS Technical Deep Dive

Devs who use Webflow's CMS API are familiar with some weird behavior in how Webflow names fields.

  1. If you create a field in the CMS named Field 1, it will appear in the API JSON as a field key of field-1.
  2. If you then rename that field to Field 2, it will still appear in the API JSON as field-1. No matter how many times you rename it.
  3. If you delete that field, save your CMS, and then create a new field named Field 1, the new field will appear in the API JSON with a number appended, as in field-1-1.
“Wait, what... ?”

Yep, you can see why this creates all kinds of confusion and challenges for API devs,

So What's going on?

Admittedly, this is pure speculation... but I'm pretty sure my guesses hit close to the mark.

And while understanding the reasons for this weird behavior won't fix the problem, understanding why these limitations exist might help you sleep a lot better at night.

Webflow's internal field-key naming mechanism goes to great lengths to avoid re-using old keys. That could be a design oversight, but more likely it is designed that way to avoid other problems related to the underlying DB or perhaps how backups & restores work.

Overall, I'd guess that the field-key-naming algo works something like this;

Why so much complexity?

Much of this is tied to the underlying technology which appears to be MongoDB.

Why do I think it's MongoDB?

  • CMS Items use 12-byte item ID's, which match MongoDB's ObjectId format.
  • References are one-way. Collection A can reference B, but you don't automatically get a multi-reference field in B pointing back to A. Relational DB's think differently from document DB's, so that stands out as document DB design aspect.
  • Multi-Ref fields are stored and ordered statically, just like they would be in a document DB.
  • When you restore from a backup, all of the item ID's change. MongoDB was designed to be more distributed than a relational db, so each system creates its own ID's rather like a UUID generator.  
  • When you export a Collection as CSV, it contains the Item ID, but when you import that CSV, you cannot map that ID to the new record. It always generates a new ID.

And more stuff, too.

I was curious, so I dug a bit deeper, and at least according to some job boards, Webflow's data storage makes use of MongoDB, Snowflake, Stitch, dbt, and Kafka. Is that stack accurate? I've no idea. But I feel validated anyway.

OK, but... So what?

Actually, it matters a lot. Let's get some geek on.

In MongoDB, each record is stored as JSON ( BSON variant ).

A record might look like this, which is very much like what we see through the CMS API.

        {
            "_archived": false,
            "_draft": false,
            "name": "Item 1",
            "slug": "item-1",
            "updated-on": "2022-10-28T21:31:13.984Z",
            "updated-by": "Person_59aa30a4b0f23d0001bac49b",
            "created-on": "2022-10-28T21:10:49.890Z",
            "created-by": "Person_59aa30a4b0f23d0001bac49b",
            "published-on": null,
            "published-by": null,
            "field-2": "f",
            "_cid": "635c45472197db43cba4a15c",
            "_id": "635c4559482d4a5baef9b764"
        }

Document db's do not have a central schema like a relational db has, so each document can be completely different. Because of this, there are no governing rules on how fields are named.

That gives you a lot of flexibility, which is important for a CMS... but the cost of that flexibility is chaos.

Old records contain old field keys. New records cannot re-use those old-field keys for new things, without breaking your data integrity.

Renaming fields is a problem because there's no schema to operate as a single point of reference. Webflow would have to go into every document and change them individually. A major db update like that could effectively bring your production site down for a few minutes while 50,000 records are updated. Such an operation could even affect performance for other users, and their sites. Webflow can't allow that. This would also explain the tight caps on CMS record counts, and the Collection List max display of 100 items.

Shared hosting means playground rules.

This is why the field-key is set at the the point you create the field, and is never changed when you rename it.

I'd also guess that when you delete a field, that field data is not actually deleted. It's just removed from the Collection table definition, to avoid the massive update costs. What that means is that old field-keys can never be re-used, since they still exist in old items.

Tips & Best Practices

So what can you do?

If you're going to be using your CMS through the API, and those field names matter to you, plan ahead.

Plan your Collection List schema before you create anything, because one you create that field, that name is set forever.

Avoid deleting fields, unless you are certain they are permanently gone, forever. If you delete a field, you will never be able to create a new field with that same field-key again in that Collection. Instead, empty it using the API, rename it in the designer as DO NOT USE, and save it for later. If you need that field-key named e.g. field-1 again, it's waiting for you.

Rename fields all you like, just remember that all the renaming in the world will not change that underlying field-key in the API.

Remember, if you muck it up, and really need those field names, your only option is to re-create the Collection entirely, which can be a huge amount of work.

None of this fixes the problems, but I hope it helps you dodge some of them.

For me, I feel more sane, when I can understand the reason those limitations exist. I'm not going crazy. It's not bad design, or inept developers... it's foundational infrastructure.

Want to support our team?
Passion drives our long hours and late nights supporting the Webflow community. Click the button to show your love.
Buy us a beer