PSD to HTML vs. modern WordPress development: what actually changed
Published in WordPress Theme Development
on September 30, 2026

ACF Local JSON: Custom Fields That Stay in Git and Stay Editable

Advanced Custom Fields gives you two ways to register a field group: through the admin UI, or in PHP code. Most tutorials pick one and stick with it. The better answer, for almost any client project, is both at once – and it takes about five minutes to set up.

The tradeoff nobody explains well

Register a field group in PHP with acf_add_local_field_group() and it becomes fast, version-controlled, deployable through your normal git workflow – and completely locked from the ACF admin screen. Anyone who wants to add a field, rename a label, or tweak an instruction has to open the code and understand PHP arrays. For a site you will maintain forever yourself, that is fine. For a site you are handing off to a client – or one you will not personally touch for months – it is a real problem: every small content-model change becomes a support ticket.

Build the field group through the admin UI instead, and you get the opposite trade: anyone can edit it, but the field definitions live only in the database, invisible to git, easy to lose on a bad migration, and impossible to diff or code-review.

ACF Local JSON solves both at once

This is a real, built-in ACF feature, not a workaround. Point ACF at a folder in your theme – conventionally acf-json/ – and two things happen automatically:

  • Whenever a field group is saved through the ACF admin UI, ACF writes a JSON file for it into that folder.
  • On every page load, ACF checks that folder and auto-loads any field group defined there as a “local” group – which still renders as a completely normal, editable screen in the ACF admin, not a locked one.

No configuration is required to enable this – ACF looks for an acf-json/ folder in your active theme by default. The result: field groups stay fully editable in wp-admin, and every change to them is a JSON file you can commit, diff, and deploy like any other theme file.

What this looks like in practice

I register new custom post types’ field groups this way for every project now. The JSON file itself needs a few required keys – key (the field group’s unique ID, conventionally prefixed group_), a location array (which post type or template it applies to), and a fields array (each field needs its own unique key, prefixed field_):

{
    "key": "group_client_details",
    "title": "Client Details",
    "fields": [
        {
            "key": "field_client_website",
            "label": "Website",
            "name": "website",
            "type": "url"
        }
    ],
    "location": [
        [
            { "param": "post_type", "operator": "==", "value": "client" }
        ]
    ],
    "show_in_rest": 1
}

That last line – show_in_rest – is worth calling out on its own: setting it to 1 exposes the field’s values through the WordPress REST API, which matters if you ever want to read or write that content programmatically instead of only through wp-admin.

One thing to watch for

If you hand-write a JSON file like the one above instead of exporting it from the ACF UI, double check whether a field group with a similar purpose already exists for that post type before adding a second one – ACF will happily register both, and having two field groups targeting the same post type is confusing for whoever edits content next, even though nothing breaks technically.

Worth setting up on your project

If you’re maintaining a WordPress site’s custom fields purely through code, or purely through the database, you’re carrying a cost you don’t have to. Get in touch if you want help setting this up properly on an existing project.