Filesystem Operations
UXP provides powerful APIs for reading, writing, creating, and deleting files. This guide will walk you through the concepts, permissions, and practical examples you need to work with the file system in your plugins
System requirements
Please make make sure your development environment uses the following minimum versions to avoid compatibility issues:
- Premiere v25.6
- UDT v2.2
- Manifest v5
Understand File System Access
The Sandbox Model
UXP uses a security model that restricts file system access by default. This protected area is called the sandbox—a set of safe locations your plugin can access without additional permissions.
In plugins, the sandbox includes:
- Plugin folder: Your plugin's installation directory (read-only)
- Data folder: Persistent storage for your plugin's data
- Temporary folder: Transitory storage that may be cleared automatically
The Temporary folder is transitory and may be cleared automatically; the Data folder is persistent across app upgrades, but will be removed on uninstall or if the user clears it. Always provide users with options to back up critical data to locations of their choice.
While the sandbox is sufficient for many use cases, you may need to access other locations—such as the user's Documents folder or a specific project directory. UXP supports this through a permission-based system.
File System Permissions
To access the file system, you must declare the localFileSystem permission in your plugin's manifest.json file.
Before you proceed
Make sure you understand how Manifest permissions work before implementing file operations in your plugin.
The detailed PermissionsDefinition reference explains all available permission options and their security implications.
The localFileSystem permission accepts three values:
"plugin"(default): provides access only to the sandbox locations. Your plugin will always be able to access the installation directory, data folder, and temporary folder."request": allows your plugin to request user permission via file picker dialogs"fullAccess": grants unrestricted access to the user's file system
Here's how to declare this permission in manifest.json:
Copied to your clipboard{// ..."requiredPermissions": {"localFileSystem": "plugin"}// ...}
Best practices for permissions
Choose the most accurate permission level for your use case. In the future, users will be asked to provide explicit consent based on the permissions you request.
While "fullAccess" might seem like the easiest option, users may be uncomfortable granting full file system access unless it's absolutely necessary—and they might deny installation of your plugin altogether. Use "request" when you need access to user-specified files, and "plugin" (or simply omit the localFileSystem field, which defaults to "plugin") when sandbox access is sufficient.
URL Schemes
UXP provides convenient URL schemes as shortcuts to specific file system locations:
| Scheme | Description | Permission Required |
|---|---|---|
plugin:/ | Plugin installation folder (read-only) | "plugin" |
plugin-data:/ | Plugin data folder (read-write) | "plugin" |
plugin-temp:/ | Plugin temporary folder (read-write) | "plugin" |
file:/ | Arbitrary file system location (full path) | "fullAccess" |
You can use these schemes in both HTML and JavaScript:
Copied to your clipboard<img src="plugin:/icons/logo.png" /><img src="file:/Users/user/Downloads/sample.png" /> <!-- update the path based on your system -->
Copied to your clipboardconst dataFile = await localFileSystem.getEntryWithUrl("plugin-data:/settings.json");
Choosing the Right API
UXP provides two APIs for file system operations, each suited to different use cases:
| API | Best For | Access Pattern |
|---|---|---|
LocalFileSystem | Multiple operations on the same file | Object references |
FS Module | Single, direct file operations | Path-based |
The LocalFileSystem API
The LocalFileSystem API is object-oriented and works with Entry references—objects that represent files and folders. This approach is ideal when you need to perform multiple operations on the same file or traverse directory structures.
Access the API:
Copied to your clipboardconst { localFileSystem, types } = require('uxp').storage;
Understanding Entries
The file system contains two types of items: files and folders. UXP represents these with the File and Folder classes, both of which extend a base class called Entry.
Some methods return an Entry because the type can only be determined at runtime. You should check the entry type before performing type-specific operations:
Copied to your clipboardconst { localFileSystem, types } = require('uxp').storage;async function createFileInFolder() {try {// Create a folder entryconst folderEntry = await localFileSystem.createEntryWithUrl("plugin-temp:/myFolder",{ type: types.folder });// Verify it's a folder before using folder-specific methodsif (folderEntry.isFolder) {const newFile = await folderEntry.createFile("data.txt", { overwrite: true });await newFile.write("This is sample content.");console.log(`File created at: ${newFile.nativePath}`);}} catch (e) {console.error("Failed to create file:", e);}}
The fs module
The fs module provides a path-based API similar to Node.js file system operations. It's ideal for straightforward, single-operation tasks like reading a configuration file or writing output.
Access the API:
Copied to your clipboardconst fs = require("fs");
Now let's explore practical examples for different permission levels.
Working with LocalFileSystem
Example 1: Accessing the Sandbox
When your plugin only needs to work with files in its own sandbox, use the "plugin" permission level—or leave the localFileSystem field empty, which defaults to "plugin" anyway.
Copied to your clipboardconst { localFileSystem } = require('uxp').storage;async function accessPluginDataFolder() {// Access the plugin's data foldertry {const dataFolder = await localFileSystem.getEntryWithUrl("plugin-data:/");console.log(`Data folder path: ${dataFolder.nativePath}`);// List all files in the data folderconst entries = await dataFolder.getEntries();console.log(`Found ${entries.length} items in data folder`);for (const entry of entries) {console.log(`- ${entry.name} (${entry.isFile ? 'file' : 'folder'})`);}} catch (e) {console.error("Failed to access data folder:", e);}}
Copied to your clipboard{"manifestVersion": 5,// ..."requiredPermissions": {"localFileSystem": "plugin"}// ...}
Example 2: Accessing Arbitrary Locations
When your plugin needs unrestricted access to the file system, use the "fullAccess" permission level. This requires you to specify absolute file paths using the file:/ scheme.
Copied to your clipboardconst { localFileSystem } = require('uxp').storage;async function accessUserDocuments() {// Access a specific location outside the sandboxtry {// For macOSconst documentsFolder = await localFileSystem.getEntryWithUrl("file:/Users/user/Documents" // 👈 update with your user);// For Windows, use: "file:/C:/Users/user/Documents"console.log(`Documents folder path: ${documentsFolder.nativePath}`);// Read a specific fileconst configFile = await localFileSystem.getEntryWithUrl("file:/Users/user/Documents/config.json" // 👈 update with your user);if (configFile.isFile) {const content = await configFile.read();console.log("Config file content:", content);}} catch (e) {console.error("Failed to access documents folder:", e);}}
Copied to your clipboard{"manifestVersion": 5,// ..."requiredPermissions": {"localFileSystem": "fullAccess"}// ...}
Remember that users may be hesitant to install plugins requesting "fullAccess". Only use this permission level when absolutely necessary. Consider using "request" instead to let users choose specific files or folders.
Example 3: User-Selected Locations
The most user-friendly approach is to let users choose which files or folders your plugin can access. Use the "request" permission level with file picker dialogs.
Copied to your clipboardconst { localFileSystem, domains, fileTypes } = require('uxp').storage;async function openUserSelectedFile() {// Present a file picker starting at the user's Desktoptry {const file = await localFileSystem.getFileForOpening({initialDomain: domains.userDesktop,types: fileTypes.text});if (!file) {console.log("User cancelled file selection");return;}// Read the selected fileconst content = await file.read();console.log(`File content:\n${content}`);console.log(`File path: ${file.nativePath}`);} catch (err) {console.error("Failed to open file:", err);}}async function saveToUserSelectedLocation() {// Present a save dialog to let the user choose where to savetry {const file = await localFileSystem.getFileForSaving("export.txt", {types: ["txt"]});if (!file) {console.log("User cancelled save operation");return;}// Write content to the selected locationawait file.write("This content was exported from the plugin.");console.log(`File saved to: ${file.nativePath}`);} catch (err) {console.error("Failed to save file:", err);}}async function selectFolderForExport() {// Let the user select a folder for batch exporttry {const folder = await localFileSystem.getFolder({initialDomain: domains.userDocuments});if (!folder) {console.log("User cancelled folder selection");return;}// Create multiple files in the selected folderfor (let i = 1; i <= 3; i++) {const file = await folder.createFile(`export_${i}.txt`, { overwrite: true });await file.write(`Content for file ${i}`);}console.log(`Created 3 files in: ${folder.nativePath}`);} catch (err) {console.error("Failed to export files:", err);}}
Copied to your clipboard{"manifestVersion": 5,// ..."requiredPermissions": {"localFileSystem": "request"}// ...}
In the example above, we use the domains.userDesktop token to get the user's Desktop folder. You can use other domains tokens, such as domains.userDocuments, domains.userDownloads, etc. Check the Domain Tokens reference for the full list.
Example 4: Remembering User Selections with Tokens
When users grant access to files or folders, you can create tokens to remember those locations across sessions—saving users from repeatedly selecting the same files.
UXP provides two types of tokens:
- Session tokens: Last until the plugin is unloaded or the application closes
- Persistent tokens: Survive across sessions until the plugin is uninstalled
Copied to your clipboardconst { localFileSystem, domains, fileTypes } = require('uxp').storage;async function selectAndRememberFile() {try {// Let the user select a fileconst file = await localFileSystem.getFileForOpening({initialDomain: domains.userDesktop,types: fileTypes.text});if (!file) {console.log("User cancelled file selection");return;}// Create a persistent token for this fileconst token = await localFileSystem.createPersistentToken(file);// Store the token for future use (e.g., in localStorage)localStorage.setItem("selectedFileToken", token);console.log(`File selected and token saved: ${file.nativePath}`);} catch (err) {console.error("Failed to create token:", err);}}async function readPreviouslySelectedFile() {try {// Retrieve the token from storageconst token = localStorage.getItem("selectedFileToken");if (!token) {console.log("No previously selected file found");return;}// Access the file using the tokenconst file = await localFileSystem.getEntryForPersistentToken(token);// Read the file contentconst content = await file.read();console.log(`File content:\n${content}`);} catch (err) {console.error("Failed to read file using token:", err);// Token may be invalid if file was deleted or movedlocalStorage.removeItem("selectedFileToken");}}
Token Storage
Store tokens in localStorage or your plugin's data folder so they persist between plugin sessions. Always handle cases where tokens become invalid (e.g., if the user deletes or moves the file).
LocalFileSystem API Reference
For complete API documentation, see:
- FileSystemProvider: main interface for file system operations.
- Entry: base class for files and folders.
- File: file-specific operations.
- Folder: folder-specific operations.
- EntryMetadata: file and folder metadata.
- Path: path manipulation utilities.
Working with the fs module
The fs module offers a simpler, path-based approach similar to Node.js. It's ideal for quick, single-operation tasks.
Example 5: Reading from the Sandbox
Read a file directly from the sandbox using a URL scheme:
Copied to your clipboardconst fs = require("fs");async function readConfigFile() {// Read a configuration file from the plugin foldertry {const content = await fs.readFile("plugin:/config.json", "utf8");const config = JSON.parse(content);console.log("Configuration loaded:", config);} catch (e) {console.error("Failed to read config file:", e);}}async function writeToDataFolder() {// Write data to the plugin's data foldertry {const data = {lastRun: new Date().toISOString(),version: "1.0.0"};await fs.writeFile("plugin-data:/state.json",JSON.stringify(data, null, 2),"utf-8");console.log("State saved successfully");} catch (e) {console.error("Failed to save state:", e);}}
Copied to your clipboard{"manifestVersion": 5,// ..."requiredPermissions": {"localFileSystem": "plugin"}// ...}
As shown in the example above, you can use the plugin:/ URL scheme in both fs and localFileSystem APIs .
Example 6: Writing to Arbitrary Locations
Write files to any location on the file system using absolute paths:
Copied to your clipboardconst fs = require("fs");async function exportToDesktop() {// Export data to the user's Desktoptry {const exportData = "Exported data from plugin";// For macOSawait fs.writeFile("/Users/user/Desktop/export.txt", // 👈 update with your userexportData,{ encoding: "utf-8" });// For Windows, use: "C:/Users/user/Desktop/export.txt"console.log("File exported to Desktop");} catch (e) {console.error("Failed to export file:", e);}}async function readFromDesktop() {// Read a file from the user's Desktop foldertry {// For macOSconst content = await fs.readFile("/Users/user/Desktop/export.txt", // 👈 update with your user"utf8");// For Windows, use: "C:/Users/user/Desktop/export.txt"console.log("File content:", content);} catch (e) {console.error("Failed to read file:", e);}}
Copied to your clipboard{"manifestVersion": 5,// ..."requiredPermissions": {"localFileSystem": "fullAccess"}// ...}
fs module API Reference
For complete API documentation, see:
Additional Considerations
Operating System Limitations
Even with "fullAccess" permission, certain system locations may be restricted by the operating system:
- macOS and Windows: Generally allow access to most user-accessible locations
- UWP (Windows Store apps): System folders are prohibited and cannot be accessed
Always handle file system errors gracefully and inform users when access is denied. Operating system security policies may prevent access to certain locations even when your plugin has the correct permissions.
Best Practices
- Choose the right permission level: start with
"plugin", upgrade to"request", and only use"fullAccess"when absolutely necessary. - Handle errors gracefully: always wrap file operations in try-catch blocks.
- Validate file paths: check that files exist before attempting to read them.
- Use appropriate encoding: specify
"utf-8"for text files to ensure proper character handling. - Provide user feedback: show progress indicators for long-running file operations.
- Clean up temporary files: delete temporary files when they're no longer needed.
When to Use Each API
| Use Case | Recommended API |
|---|---|
Multiple operations on the same file | LocalFileSystem |
Traversing directory structures | LocalFileSystem |
Working with file metadata | LocalFileSystem |
Creating persistent tokens | LocalFileSystem |
Quick read/write operations | FS Module |
Simple path-based operations | FS Module |
Familiarity with Node.js fs API | FS Module |
Reference Material
- FileSystemProvider: main interface for file system operations.
- Entry: base class for files and folders.
- File: file-specific operations.
- Folder: folder-specific operations.
- EntryMetadata: file and folder metadata.
fsmodule: complete file system API reference.- Path: path manipulation utilities.
- LocalStorage: persistent data storage for tokens.
- Manifest Permissions: overview of all permissions.
- Local File System Permission: detailed permission documentation.
Summary
The Sandbox Model: By default, plugins can only access safe locations (plugin folder, data folder, and temporary folder) without additional permissions. The plugin folder is read-only, while data and temporary folders are read-write but may be cleared automatically.
File System Permissions: Declare the
localFileSystempermission in yourmanifest.jsonwith three possible values:"plugin": Access only sandbox locations (default, most secure)"request": Present file picker dialogs for user-selected files and folders (recommended for user data)"fullAccess": Unrestricted file system access (use sparingly, may deter users from installing)
URL Schemes: UXP provides convenient shortcuts to file system locations:
plugin:/for the plugin folder (read-only)plugin-data:/for persistent plugin dataplugin-temp:/for temporary storagefile:/for absolute paths (requires"fullAccess")
Two File System APIs: Choose based on your use case:
- LocalFileSystem API: Object-oriented, uses Entry references (File and Folder objects), ideal for multiple operations, directory traversal, and working with metadata
- fs module: Path-based like Node.js, ideal for quick single operations and simple read/write tasks
Persistent Access with Tokens: When users grant access to files or folders via
"request"permission, create session tokens (temporary) or persistent tokens (survive across sessions) to remember these locations without repeatedly prompting users.Common Patterns:
- For configuration files in your plugin folder: Use
fs.readFile("plugin:/config.json") - For saving plugin state: Use
fs.writeFile("plugin-data:/state.json") - For user-selected files: Use
localFileSystem.getFileForOpening()with"request"permission - For batch operations: Use
LocalFileSystemAPI with folder traversal - For remembering user selections: Create persistent tokens and store them in
localStorage
- For configuration files in your plugin folder: Use

