Apple property list parser/builder for Node.js and browsers. Supports XML, binary (bplist00), and OpenStep formats.
DOMParser in browsers (zero dependencies)npm install plist
import { parse, build } from 'plist';
// Parse any plist format (auto-detected)
const obj = parse('<plist version="1.0"><string>Hello!</string></plist>');
console.log(obj); // "Hello!"
// Build an XML plist from a JS object
const xml = build({ name: 'My App', version: 42 });
console.log(xml);
import { readFileSync } from 'node:fs';
import { parse } from 'plist';
const xml = readFileSync('Info.plist', 'utf8');
const obj = parse(xml);
Binary plists (bplist00) are auto-detected when passed as a Uint8Array or ArrayBuffer. You can also use parseBinary() directly:
import { readFileSync } from 'node:fs';
import { parse, parseBinary } from 'plist';
// Auto-detected from binary data
const buf = readFileSync('Info.plist');
const obj = parse(new Uint8Array(buf));
// Or use parseBinary() directly
const obj2 = parseBinary(new Uint8Array(buf));
The old-style ASCII format (used by defaults read on macOS) is auto-detected when the input starts with { or (:
import { parse, parseOpenStep } from 'plist';
// Auto-detected
const obj = parse('{ CFBundleName = "My App"; CFBundleVersion = 42; }');
// Or use parseOpenStep() directly
const obj2 = parseOpenStep('( item1, item2, item3 )');
import { build } from 'plist';
const xml = build({
CFBundleName: 'My App',
CFBundleVersion: '1.0',
LSRequiresIPhoneOS: true,
UISupportedInterfaceOrientations: [
'UIInterfaceOrientationPortrait',
'UIInterfaceOrientationLandscapeLeft',
],
});
Output:
<?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>CFBundleName</key>
<string>My App</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
</array>
</dict>
</plist>
import { writeFileSync } from 'node:fs';
import { buildBinary } from 'plist';
const data = buildBinary({
CFBundleName: 'My App',
CFBundleVersion: '1.0',
});
writeFileSync('Info.plist', data);
| Plist Type | JavaScript Type |
|---|---|
<string> | string |
<integer> | number |
<real> | number |
<true/> / <false/> | boolean |
<date> | Date |
<data> | Uint8Array |
<array> | Array |
<dict> | Object |
In bundled applications (Vite, webpack, etc.), just import normally — the browser-optimized build is selected automatically via conditional exports:
import { parse, build } from 'plist';
The browser build uses native DOMParser and string-based XML building, so @xmldom/xmldom and xmlbuilder are not included in the bundle.
Try the interactive playground →
parse(input)Parse a plist. Format is auto-detected.
string | Uint8Array | ArrayBufferPlistValueparseBinary(data)Parse a binary plist (bplist00).
Uint8ArrayPlistValueparseOpenStep(input)Parse an OpenStep/ASCII plist.
stringPlistValuebuild(obj, opts?)Build an XML plist string.
PlistValueboolean (default: true) — pretty-print with indentationstring (default: " ") — indentation stringstring (default: "\n") — newline stringstringbuildBinary(obj)Build a binary plist (bplist00).
PlistValueUint8ArrayPlistValuetype PlistValue =
| string
| number
| boolean
| Date
| Uint8Array
| PlistValue[]
| { [key: string]: PlistValue }
| null;