PLIST File Documentation


Summary

A plist (Apple Property List) file stores settings and structured data for macOS and iOS as keyed dictionaries, arrays, strings, numbers, dates and booleans. It comes in two encodings under one extension: human-readable XML, or a compact binary form that starts with the bytes bplist00. Its MIME type is application/x-plist. Open an XML .plist in any text editor; convert a binary one with plutil -convert xml1 file.plist on a Mac. Most plists are app internals you should not hand-edit blindly.

Technical details

FeatureValue
Full nameApple Property List
File extension.plist
MIME typeapplication/x-plist
Format typeSerialized settings: XML text or binary bplist
DeveloperApple (originally NeXT)
IntroducedNeXTSTEP (late 1980s); XML/binary forms with Mac OS X 10.0 (2001)
EncodingsXML, binary (bplist00), legacy NeXT/OpenStep ASCII
Binary magic62 70 6C 69 73 74 30 30 (“bplist00”)
XML header<?xml + <!DOCTYPE plist + <plist version…>
Value typesdict, array, string, integer, real, true/false, date, data
Byte orderBig-endian (binary form)
Typical useInfo.plist in app bundles; prefs in ~/Library/Preferences
Convert toolplutil (macOS), plistutil (Linux/Windows)
EditorXcode property-list editor; any text editor (XML)
Managed bycfprefsd daemon; defaults command
Open standardPartial (public DTD; binary format documented by Apple/libplist)
Related extensions.xml, .mobileconfig, .strings, .entitlements, .json
Specificationdeveloper.apple.com — About Property Lists
File signature (magic bytes)
62 70 6C 69 73 74 30 30

Offset 0, 8 bytes, binary plists only. In ASCII this reads bplist00, where 00 is the format version. If a file starts with these bytes it is the compact binary encoding and will look like gibberish in a text editor. An XML plist has no fixed magic: it begins with <?xml version="1.0"…>, then a <!DOCTYPE plist PUBLIC…> declaration pointing at Apple’s DTD, then the <plist> root. Convert binary to readable XML with plutil -convert xml1 file.plist.

What is a plist file?

A property list, or plist, is Apple’s standard way of serialising structured settings: dictionaries, arrays, strings, numbers, booleans, dates and raw data. The concept comes from NeXTSTEP in the late 1980s and became central to Mac OS X on its 2001 release and later to iOS. Every macOS and iOS app ships an Info.plist that declares its bundle identifier, version, required capabilities and permission usage strings; user preferences are stored as plists under ~/Library/Preferences, managed by the defaults system and the cfprefsd daemon.

The wrinkle that trips people up is that one extension covers two very different encodings. A plist can be a readable XML document, or a compact binary blob that begins with the bytes bplist00 and looks like garbage in a text editor. There is also a legacy NeXT/OpenStep ASCII form, now rare. The data is identical across encodings and round-trips losslessly between them; only the bytes on disk differ. The sections below cover the value model, the XML form, the binary form field by field, and why editing a live preferences plist by hand often does not stick.

The value model: eight types under a root container

Whatever the encoding, a plist represents the same small, fixed set of types. The document is a single root value, almost always a dictionary or an array, which nests the rest.

plist typeXML tagHolds
Dictionary<dict>ordered <key> / value pairs
Array<array>an ordered list of values
String<string>Unicode text
Integer / real<integer> / <real>numbers
Boolean<true/> / <false/>a flag
Date<date>ISO-8601 timestamp
Data<data>base64-encoded bytes

A dictionary is where most configuration lives: each entry is a <key> naming a value that follows it. This is the same conceptual model as JSON, which is why plutil can convert many plists to JSON; the differences are that plist adds first-class date and data types JSON lacks, and that a plist dictionary’s keys are written as separate elements rather than as "key": value pairs.

The XML form: DOCTYPE, DTD and structure

An XML plist is a normal XML 1.0 document with a specific document type. It has no binary magic number; it is recognised by its opening declarations.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleIdentifier</key>
    <string>com.example.app</string>
    <key>CFBundleVersion</key>
    <string>1.2.0</string>
    <key>LSMinimumSystemVersion</key>
    <string>12.0</string>
</dict>
</plist>

The <!DOCTYPE> line points at Apple’s public DTD, which formally defines the allowed elements. The single <plist> root wraps one value. Because it is plain UTF-8 text, this form opens in any editor on any OS, which is why so much troubleshooting advice can say “edit the plist” without naming a Mac-only tool. The trade-off is size and parse speed, which is what the binary form addresses.

The binary form: header, objects, offset table, trailer

A binary plist is built for apps to load quickly and store compactly. It has four regions in order: an 8-byte header, an object table, an offset table, and a 32-byte trailer at the very end.

bplist layout
  header        "bplist00"                  (8 bytes)
  object table  every value, each prefixed by a 1-byte marker
  offset table  file offset of each object (uint of fixed width)
  trailer       32 bytes, at end of file:
                6 unused
                1  offset-table entry size  (1-4 bytes)
                1  object-reference size     (1-4 bytes)
                8  number of objects
                8  index of the top (root) object
                8  offset where the offset table starts

Each object in the object table starts with a single marker byte whose high nibble encodes the type (integer, string, dict, array and so on) and whose low nibble usually encodes the length, with an escape for larger sizes. Containers do not store their children inline; they store object references, which are indices into the offset table. The offset table then lists the absolute file offset of every object, so reference n resolves to the object at the nth offset. The trailer is read first (parsers seek to the last 32 bytes): it gives the byte-width of an offset-table entry, the byte-width of an object reference, the total object count, which object is the root, and where the offset table begins. From those five numbers a reader can walk the whole graph. This indirection is what lets a binary plist deduplicate repeated values and stay small, and it is why the format is faster for an app to load than re-parsing XML.

Converting between encodings with plutil

Because the two encodings carry the same data, macOS ships plutil to move between them and to validate syntax. This is the load-bearing command for anyone facing an unreadable plist.

plutil -convert xml1  file.plist   # binary -> readable XML
plutil -convert binary1 file.plist # XML -> compact binary
plutil -convert json  file.plist   # -> JSON (data/date become base64/strings)
plutil -p file.plist               # print a human-friendly tree
plutil -lint file.plist            # validate syntax

On Linux and Windows the equivalent is plistutil from libplist (part of libimobiledevice, the toolkit that reads iPhone backups). Converting to JSON is lossy in one direction: a plist <data> becomes a base64 string and a <date> becomes a text string, because JSON has no native type for either, so a JSON → plist round trip does not restore those types automatically.

Why hand-editing a preferences plist may not stick

On modern macOS the preference plists under ~/Library/Preferences are not simple files an app reads on demand. They are cached in memory and written back by the cfprefsd daemon, which owns the in-memory copy while an app is running. Editing such a plist by hand in a text editor while the owning process is live often has no effect, because cfprefsd later flushes its cached version over your change. The supported route is the defaults command (for example defaults write com.example.app SomeKey -bool true), which goes through the same daemon so the change is seen and persisted. This caching is specific to the preferences domain; a plist you own, such as one inside your own app bundle or a config file, can be edited directly.

Frequently asked questions

Why is my .plist file full of unreadable characters?

It is a binary plist, not XML. The file starts with the bytes bplist00 and stores its values in a packed object table, so a text editor shows raw bytes. Convert it to readable XML first with plutil -convert xml1 file.plist on macOS, or plistutil on Linux and Windows, then open the result.

Can I open a plist on Windows?

An XML plist opens in any text editor such as VS Code or Notepad++, because it is plain UTF-8 text. A binary plist needs converting first, since Windows has no built-in plist support; use plistutil from libimobiledevice to turn bplist00 data into XML, then read it.

References