Understanding the File System Access API
Modern web applications can interact directly with the user's file system, enabling powerful document editing, data export, and local file management capabilities directly in the browser. The File System Access API represents a significant advancement for web development, opening up functionality that has traditionally been reserved for native applications.
This API allows users to work with their files directly from the browser, providing a seamless experience that bridges the gap between web and desktop applications. By using handle-based objects to represent files and directories, developers can build sophisticated file management features that rival native software while maintaining the accessibility and deployment advantages of web technology.
The File System Access API provides comprehensive file handling capabilities
Direct File Access
Read and write files directly on the user's device with their explicit permission through secure picker dialogs.
Handle-Based Architecture
Use FileSystemHandle objects to represent files and directories, enabling persistent access across sessions.
Stream-Based Writing
Write data efficiently using FileSystemWritableFileStream with support for Blob, String, and ArrayBuffer inputs.
Directory Management
Navigate and manage directory structures with FileSystemDirectoryHandle for complex file organization.
The Modern Approach: Using showSaveFilePicker
The showSaveFilePicker() method is the cornerstone of the File System Access API for saving files. This method displays a file save dialog that allows users to choose where to save their file and what to name it. The API returns a FileSystemFileHandle that provides access to the selected file for subsequent operations.
Key Implementation Points
The API requires a secure context (HTTPS) and must be called from the top-level frame, not inside an iframe. This security model ensures that users maintain control over their file system access and prevents malicious websites from silently modifying files.
Required browser features:
- Secure context (HTTPS)
- Not running in an iframe
- Browser support (Chrome 86+, Edge 86+)
The types option allows you to suggest file types and their associated MIME types, helping the file picker dialog show appropriate filters and giving users guidance about what formats your application supports. This level of integration with the native file system is a key advantage of modern web applications built with advanced browser APIs.
1async function saveFileModern(blob, suggestedName) {2 // Feature detection3 const supportsFileSystemAccess =4 'showSaveFilePicker' in window &&5 window.isSecureContext &&6 window.self === window.top;7 8 if (!supportsFileSystemAccess) {9 return saveFileFallback(blob, suggestedName);10 }11 12 try {13 // Show the file save dialog14 const handle = await window.showSaveFilePicker({15 suggestedName: suggestedName,16 types: [17 {18 description: 'Text Files',19 accept: { 'text/plain': ['.txt'] },20 },21 ],22 });23 24 // Create a writable stream and write the blob25 const writable = await handle.createWritable();26 await writable.write(blob);27 await writable.close();28 29 console.log('File saved successfully');30 return true;31 } catch (err) {32 if (err.name !== 'AbortError') {33 console.error('Save failed:', err.name, err.message);34 }35 return false;36 }37}The Classic Approach: Download Attribute
For browsers without File System Access API support, the traditional anchor download attribute provides universal compatibility. This approach creates a temporary download link and programmatically triggers it to initiate the download. The download attribute on anchor elements tells the browser to download the linked resource instead of navigating to it.
When combined with URL.createObjectURL(), you can create downloadable content from JavaScript-generated Blob data. This method has been available in browsers for many years and provides a reliable fallback for modern file system operations.
Browser support: Universal (Chrome 15+, Firefox 20+, Safari 10.1+, Edge 13+)
The classic approach is essential for ensuring your file-saving functionality reaches all users, regardless of their browser choice or version. By implementing both approaches through progressive enhancement, you create a robust solution that works everywhere while taking advantage of advanced capabilities where supported.
1function saveFileFallback(blob, suggestedName) {2 // Create a Blob URL from the blob data3 const blobURL = URL.createObjectURL(blob);4 5 // Create an anchor element for download6 const a = document.createElement('a');7 a.href = blobURL;8 a.download = suggestedName;9 a.style.display = 'none';10 11 // Add to DOM and click programmatically12 document.body.appendChild(a);13 a.click();14 15 // Clean up after a short delay16 setTimeout(() => {17 URL.revokeObjectURL(blobURL);18 a.remove();19 }, 1000);20}Progressive Enhancement Pattern
The most robust implementation combines both approaches using feature detection. Try the modern File System Access API first, then fall back to the classic download approach for unsupported browsers. This ensures your file-saving functionality works everywhere while providing an enhanced experience where supported.
Progressive enhancement is essential for web applications that need to reach the widest possible audience. By detecting feature availability at runtime, you can provide the best possible experience to users with modern browsers while maintaining full functionality for everyone else.
Implementation strategy:
- Detect File System Access API support
- Attempt modern save if supported
- Fall back to classic download if needed
- Handle errors gracefully for both paths
This approach ensures that your application remains functional and user-friendly regardless of the browser environment, while still taking advantage of advanced capabilities when available.
1async function saveFile(blob, suggestedName) {2 // Feature detection3 const supportsFileSystemAccess =4 'showSaveFilePicker' in window &&5 window.isSecureContext &&6 (() => {7 try {8 return window.self === window.top;9 } catch {10 return false;11 }12 })();13 14 // Try modern API first15 if (supportsFileSystemAccess) {16 try {17 const handle = await showSaveFilePicker({ suggestedName });18 const writable = await handle.createWritable();19 await writable.write(blob);20 await writable.close();21 return { success: true, method: 'modern' };22 } catch (err) {23 if (err.name === 'AbortError') {24 return { success: false, cancelled: true };25 }26 // Fall through to classic method27 }28 }29 30 // Fallback for unsupported browsers31 const blobURL = URL.createObjectURL(blob);32 const a = document.createElement('a');33 a.href = blobURL;34 a.download = suggestedName;35 a.style.display = 'none';36 document.body.appendChild(a);37 a.click();38 39 setTimeout(() => {40 URL.revokeObjectURL(blobURL);41 a.remove();42 }, 1000);43 44 return { success: true, method: 'classic' };45}Best Practices for File Handling
Performance Considerations
When working with large files, streaming writes through createWritable() provides better memory efficiency than loading entire files into memory. The FileSystemWritableFileStream operates in-place on a single file on disk, which is particularly beneficial for large documents or media files. This approach prevents browser memory issues that can occur when loading massive files into RAM.
For applications that frequently read or write files, consider using the Origin Private File System (OPFS), which provides highly optimized file access within your application's sandbox. The OPFS is private to the origin and invisible to the user, but offers superior performance for local file operations.
Error Handling
Handle common errors gracefully to provide a smooth user experience:
- AbortError: User cancelled the file picker - treat as intentional cancellation, not failure
- NotAllowedError: Permission was denied - explain why file access is needed
- NotFoundError: Specified file doesn't exist - guide user to select a valid location
- SecurityError: Context is not secure - ensure HTTPS is properly configured
File Type Suggestions
Use the types option to suggest appropriate file types for better user experience:
{
types: [
{
description: 'JSON Documents',
accept: { 'application/json': ['.json'] },
},
{
description: 'All Files',
accept: { '*': ['.*'] },
},
]
}
Security Model
The File System Access API was designed with security as a primary concern. Access to file and directory data is explicitly disallowed unless the user grants permission through the picker dialog. This user-mediated access ensures that web applications cannot read or modify files without the user's knowledge and consent. The API is only available in secure contexts (HTTPS) to protect user data. Implementing proper security practices is essential when working with file system access in web applications.
| Browser | File System Access API | Download Attribute |
|---|---|---|
| Chrome | 86+ | 15+ |
| Edge | 86+ | 13+ |
| Firefox | Not supported | 20+ |
| Safari | Not supported | 10.1+ |
| Opera | 86+ | 12+ |