macOS Read-Only Root: Create a Path with synthetic.conf

Content edited . This editorial update does not represent a new runtime test.

On this page

If sudo mkdir /photo returns Read-only file system on macOS, sudo cannot make the protected system volume writable. If an existing application really needs a root-level path, a synthetic link can map that name to a writable data directory. If you can change the application configuration, using the data directory directly is simpler.

Choose the appropriate path first

Situation Appropriate next step
You control the application’s storage setting Use a directory owned by the intended account; no root alias is needed.
A tool requires a fixed root path such as /photo Evaluate a two-column synthetic.conf entry pointing to an existing directory.
An external disk, ordinary user folder or network mount is read-only Investigate that volume’s format, mount state and permissions; this guide does not repair those problems.
You need a root mount point for another filesystem A one-column synthetic directory is a different configuration; it is not general writable storage.

The original note targeted Monterey. Apple’s local synthetic.conf(5) manual describes synthetic entities created during early boot; Apple Developer Technical Support recommends synthetic symlinks for common root-path needs. This does not unlock the system volume or require disabling SIP.

Inspect names and existing manifests

Use the manual shipped with the macOS version you will configure:

sw_vers
man synthetic.conf
ls -ld /photo
ls -l /etc/synthetic.conf /etc/synthetic.d

A missing file or directory is an inspection result, not an instruction to delete or recreate an unrelated path. Check both /etc/synthetic.conf and any files under /etc/synthetic.d. If several manifests define the same name, the manual says the selected definition is undefined. Resolve that conflict before adding an entry.

A single-column entry creates an empty synthetic directory; you cannot create ordinary files inside it. A two-column entry creates a link to the second column’s target. Choose the two-column form for this example.

Prepare the real directory and preserve configuration

Replace /Users/alex/photo with the actual data location. Create it as the account that will own the files, then check access:

mkdir -p /Users/alex/photo
ls -ld /Users/alex/photo
test -d /Users/alex/photo && test -w /Users/alex/photo

The test commands produce no success text; inspect their exit status. A service running as another account needs its own access check. Do not recursively change ownership of unrelated data to make this example pass.

Before editing, preserve a copy of any existing manifest you will change and record whether /etc/synthetic.conf was absent:

audit_backup_dir=$(mktemp -d "$HOME/synthetic-conf-backup.XXXXXX") || exit 1
if test -e /etc/synthetic.conf; then
    cp /etc/synthetic.conf "$audit_backup_dir/synthetic.conf" || exit 1
else
    printf '%s\n' 'synthetic.conf was absent' > "$audit_backup_dir/state.txt"
fi
printf 'Backup directory: %s\n' "$audit_backup_dir"

Save the printed backup location before rebooting; the shell variable will not survive a restart. If you edit a manifest in synthetic.d, back up that specific file too. These commands save evidence and do not alter the active configuration.

Keep existing entries intact. Edit the manifest with an administrator-capable editor rather than overwriting it with a one-line redirection. Add only an unused root name, a literal tab, and the target:

photo	/Users/alex/photo

The example uses an absolute target. Apple’s manual also shows root-relative targets such as Users/me/photo; whichever form you choose, verify the resulting link resolves to the intended location. The first column is photo, not /photo.

Check the saved separator:

cat -vet /etc/synthetic.conf

For the example, expect photo^I/Users/alex/photo$: ^I displays the tab and $ displays the line ending. Spaces or the two characters backslash and t are not a literal tab. Review the entire manifest for duplicate names and accidental changes before rebooting.

Plan the reboot for the machine being configured. Then inspect:

ls -ld /photo
readlink /photo
test -d /photo

A link can exist while its destination is missing. readlink prints the stored target; test -d follows the link and checks whether it resolves to a directory. Check that the printed target and the account’s permissions match the intended data location.

To test writing as the intended account, create only a temporary probe in that directory, then remove that exact probe:

audit_probe=$(mktemp /photo/.synthetic-write-check.XXXXXX) || exit 1
printf '%s\n' 'synthetic link write check' > "$audit_probe"
cat "$audit_probe"
rm "$audit_probe"

Do not run the write test as root if the application normally uses an unprivileged account. Passing it demonstrates access for that account, not for every service.

Diagnose failures and undo only this entry

Observation Check
/photo is absent after editing Saved tab-separated entry, name conflicts, and whether the machine has actually restarted.
Link exists but test -d /photo fails Missing or incorrect target; the link alone is not proof of usable storage.
Directory resolves but writing fails Permissions for the actual application account.
A different target appears Existing names in both the main manifest and synthetic.d.

To roll back, remove only the entry you added from the manifest you edited, preserve unrelated entries, and restart again. Synthetic entities cannot simply be deleted at runtime. Confirm the root alias has disappeared and the real data directory remains intact. Do not delete the target as part of removing its alias.

What was actually checked

On October 14, 2026, a read-only inspection on an arm64 Mac running macOS 27.0 (build 26A428) found a pre-existing two-column manifest and its root symlink. cat -vet showed a real tab and readlink returned the configured target, but the target directory was absent. This is direct evidence that a synthetic link can exist without usable backing storage; it is not a successful new setup.

A temporary-directory fixture checked tab display and ordinary symlink resolution separately. No /etc file was changed, no new root entity was created, no reboot or synthetic-path write test was performed, and no VM was available for a full create/reboot/rollback test. The walkthrough still requires those checks on the reader’s target system; the fixture does not exercise macOS boot-time synthesis.

Related: Xcode disk-space troubleshooting concerns available storage, not root write permissions.

← All articles