ACF Field Sync
How to sync ACF field groups across environments using Local JSON — setup, workflow, and gotchas.
ACF Local JSON saves field group definitions as .json files on disk instead of only in the database. This lets you version-control field groups and sync them across environments via git.
Setup
Create the folder in your theme:
1
wp-content/themes/your-theme/acf-json/
ACF detects this folder automatically and starts saving JSON files there. No filter required unless you need a custom path.
The sync workflow
- Edit a field group in the ACF UI on your local environment
- ACF writes the updated
.jsonfile toacf-json/ - Commit and push the file
- On the target environment (staging/production), pull the branch
- Go to Custom Fields > Sync Available — ACF shows any field groups where the JSON is newer than the database
- Click Sync to write the JSON into the database
If you skip step 6, the JSON is loaded at runtime but the field group won’t be editable in the ACF UI on that environment.
What syncing actually does
ACF stores field group definitions as custom post type records in wp_posts. The JSON file is a snapshot of that same data on disk. Syncing reads the JSON and writes those records into the database.
Fields work without syncing. ACF loads the JSON at runtime when rendering edit screens, so fields appear on posts and pages immediately after a deploy — no sync required.
The “Sync Available” notice means the DB record is stale relative to the JSON. It’s a housekeeping mismatch, not a broken state.
For developers: Skipping sync is safe for day-to-day use. It becomes a trap if someone opens the ACF field group editor on an unsynced environment — they’ll be editing the old DB record, not the JSON, and any saves will create a conflict.
For admins: Fields appear and save data regardless of sync state. If ACF admin is visible and they open Custom Fields, they’ll see the sync banner. Clicking Sync overwrites the DB with the JSON — that’s the correct action. The risk is if they edit fields before syncing.
Disable ACF admin on staging and production
Prevents accidental field edits in non-local environments overwriting your JSON. Add to functions.php:
1
2
3
4
5
6
7
add_filter( 'acf/settings/show_admin', function() {
$protected = [
'https://staging.example.com',
'https://example.com.au',
];
return ! in_array( get_bloginfo( 'url' ), $protected );
});
Use environment variables instead of hardcoded URLs if available:
1
2
3
add_filter( 'acf/settings/show_admin', function() {
return getenv( 'WP_ENV' ) === 'local';
});
Conflict: DB is newer than JSON
This happens when someone edits fields directly on staging or production. ACF will show a “DB is newer” warning on the field group list.
Resolution: If local JSON is the source of truth, re-sync from JSON. If the remote DB has legitimate changes, export the field group to JSON from that environment first, commit it, then sync on all other environments.
Gotchas
- The
acf-json/folder must be writable by the web server for auto-save to work - Child themes need their own
acf-json/folder — ACF won’t auto-save to the parent theme’s folder - If you use a plugin-based MU approach, set a custom load path pointing to the plugin’s folder
published: falsefield groups are still saved as JSON — don’t mistake a missing Sync notice for “no changes”