- file:/// allows you to navigate the local file system from the browser in Windows y Android.
- The File System Access API offers advanced read and write capabilities to local files and directories.
- Security is based on explicit user permissions and clear control over which routes are exposed.
- There are polyfills and libraries that combine this API with classic methods when there is no native support.
Using your browser as a small file explorer is possible and, when used effectively, can be incredibly useful. From opening a simple local document with `file:///` to working with the powerful File System Access API , modern browsers offer far more possibilities than we typically use.
Throughout this guide we will see, step by step, how to open local files in the web browser using file:/// in Chrome, Edge and Firefox , how to turn the browser itself into a basic file explorer in Windows and Android, and how developers can go a step further thanks to the File System Access API to read, write and manage local files and folders from a web application.
What does it really mean to open local files with file:///
When you write a route that starts with file:/// in the browser's address bar, You're telling the browser to access the local file system instead of the internet.That is, to open something that is on your own device: a hard drive, internal memory, or an SD card.
This special URL scheme (file:///) It works similarly to typing C: in Windows or / in Linux and macOSIt's just adapted to the browser's logic. From there, what you'll see is a kind of list of folders and files, without any frills: names, sizes, modification date, and little else.
Of course, it must be borne in mind that Browsers treat these local routes with many security restrictions.For example, a website you visit from the internet cannot, by default, freely read your local files just because you open a URL with file:///An explicit gesture or permission from the user is always required.
Using the browser as a file explorer on Android
Many Android phones don't include a decent file manager from the manufacturer, or the one that comes pre-installed is rather limited. In those cases, using Chrome, Edge, or another Chromium-based browser as a makeshift file explorer can get you out of a bind.
The trick is very simple: Open your Chromium-based browser (Chrome, Edge, Brave, etc.) and type in the address bar file: /// sdcard /Android identifies the storage main internal as sdcard, in a very similar way to how Windows uses C: for the main drive.
When you enter that address, your browser will usually ask for permission to access your internal storage. Once you grant that permission, an index of your internal storage's root folders will appear . From there, you can navigate in and out of folders just as if you were browsing a website with links.
In each folder you will see both subfolders and files. Files are displayed with their full name, including the extension, their size, and the last modification date.The following are also listed: hidden folders, which in Android usually begin with a period, like .nomedia or other similar ones.
Although the list is very limited, most modern browsers can directly open many types of files by tapping them : images, videos, audio, text documents, etc. There are no thumbnails or previews, but simply tapping on the file name will cause the browser to attempt to display or play it.
Turn Chrome and Edge into a small file explorer on your PC
On desktop computers, both on Windows and other systems, you can also use Chrome, Edge, and other Chromium-based browsers to navigate your local drives with file:/// . The principle is the same as on Android, but the path is different.
If you use Windows, the primary drive is most commonly C:. In that case, type in the address bar file:///C: and press EnterThe browser will show you the contents of the root of that drive: folders such as Windows, Program Files, Usuarios, etc.
If you have more drives or partitions, You can replace the letter in the URL with the corresponding one.. For example, file:///D: for another album or file:///E: for a memory USB that it was mounted with that letter. From there, click on the folders to move forward and use the browser's back button to go back.
Just like on Android, in each folder you'll see files and subfolders with their size, modification date, and extension displayed . Thumbnails and fancy icons aren't generated, but it's sufficient for locating a specific file or getting a quick overview of a directory's structure.
Most Chromium browsers allow you to directly open multimedia files and even some document formats simply by clicking on them. Images, videos, audio files, and plain text files are displayed quite naturally within the tab.
Open local files in Chrome and Firefox without manually typing file:///
In addition to typing routes with file:///Browsers include shortcuts designed specifically to quickly open local files. In Chrome, for example, you can use the keyboard shortcut Ctrl + O (Control + O) when the browser window is active.
Clicking that shortcut opens the operating system's typical "Open File" dialog box . Simply locate the file you want, select it, and confirm. Chrome will load it in the current tab or a new one, depending on the file type and your preferences.
Firefox offers several options. On the one hand, You can go to the main menu and choose the "Open file..." optionwhich does exactly the same thing: display the system's file selection window. Alternatively, you can directly type a path like this into the address bar: file:///// so that the browser starts by displaying the contents of drive C: in Windows.
With any of these methods, the practical result is that the browser becomes a local file viewer . This can help when Windows Explorer crashes, when you're having trouble with your usual file manager, or simply when you want to open a type of document that the browser handles particularly well.
The File System Access API: the leap from viewer to editor
Everything we've seen so far relies on the "manual" use of file:/// and file open dialog boxes—that is, things the user does manually. But for some time now, Chromium-based browsers have incorporated the File System Access API , which gives web applications the ability to work with local files in a much more advanced way.
This API allows a website, after requesting your permission, to read and save changes directly to files and folders on your device . Thanks to this, it's possible to create robust text editors, programming IDEs , photo and video editors, project managers, and many other tools directly in your browser—tools that previously only made sense to develop as desktop applications.
It is important not to confuse this modern API with older or obsolete ones. It's not the same as the interface FileSystem nor the File and Directory Entries API nor the old “File API: Directories and System” specification, which proposed other mechanisms for handling file hierarchies and sandbox storage areas.
The current File System Access API has been designed with particular attention to security, permissions, and user experience . It always requires explicit actions (such as clicking a button) to open the file or directory selector, and the user is always clear about the exact paths they are granting access to.
In terms of compatibility, the API works in most Chromium-based browsers on Windows, macOS, Linux, ChromeOS, and Android . A notable exception is Brave, where it's still necessary to enable a flag to use it. Other non-Chromium browsers may not implement it or may only implement it partially.
Check if the browser supports the File System Access API
As a developer, the first thing you want to know is whether the user's browser supports this API before attempting to use it. The simplest way is to check if the corresponding file selection methods exist in the global object.for example, by checking if showOpenFilePicker is available from window (o self in a worker).
The typical pattern is something like this: “if 'showOpenFilePicker' is set to self, then I can use the API; otherwise, I must resort to an alternative method .” This allows for the implementation of hybrid solutions where, if support is available, the advantages of the API are leveraged, and if not, traditional techniques such as file upload forms are used.
It's also a good idea to test on the target browsers and different operating systems , because even though the base is Chromium, some manufacturers may enable or disable specific features for security, policy, or performance reasons.
First example: opening a local file from a web app
One of the classic examples for understanding this API is building a single-file text editor that allows you to open, modify, and save a document . It doesn't need to be spectacular: simply reading and writing plain text is enough to illustrate how it works.
The entry point here is the method window.showOpenFilePicker(). This method, which can only be called in a secure context (HTTPS) and in response to a user gestureIt displays a native dialog for the user to choose a file. Once selected, it returns an array of handles, typically with a single FileSystemFileHandle.
This handle stores all the information and methods necessary to work with the chosen file. It's a good idea to save a reference to this handle, because you'll use it later to read the file, save changes, or perform any other operation . As long as you maintain this handle and the user hasn't revoked permissions, your app will be able to interact with the file.
Once you have the FileSystemFileHandle, you can obtain the object File real calling handle.getFile()This object File It contains the file's data as a blob, and you can access its contents using methods such as text(), arrayBuffer(), stream() o slice() if you need random access.
In practice, for a simple text editor, the usual thing is to use file.text() to obtain the complete content as a stringand put that text into a <textarea> so that the user can edit it. It's important to note that the object File It ceases to be valid if the file is modified on disk by another means, in which case it is advisable to call again. getFile().
Save changes: write to the local file system
To save what the user has edited, the API offers two typical methods: a "simple" save that overwrites the original file and a "Save As" that creates a new file . The fundamental difference is whether you already have a handle to the destination file or if you need the user to choose a new path and name.
When you want to create a new file or save a copy with a different name, you should use showSaveFilePicker()This method opens the file selector in saved mode, allowing the user to specify the name, folder, and extension. You can provide options to suggest file types, for example, indicating that it's a text document and that the preferred extension is . .txt.
An important detail is that You should call showSaveFilePicker() directly in response to the user's gesture (for example, clicking the "Save" button) and don't delay it while you're doing heavy processing. If you do all the preliminary work and then, with a delay, try to open the dialog, the browser might throw a security error because it no longer considers that you're "handling a user gesture."
Once you have a FileSystemFileHandle pointing to the file where you want to save, The next step is to create a FileSystemWritableFileStream using fileHandle.createWritable()This stream is the one you'll use to write the data. If the browser detects that you don't yet have write permission, it will display a permissions dialog; if the user denies it, the call will throw an exception.
With the stream in hand, You simply call writable.write(contenido) with a string, a Blob, or a BufferSourceYou can even directly pipe the body of an HTTP response into the stream with response.body.pipeTo(writable)When you finish typing, you close the transmission with writable.close(), which is the moment when the changes are consolidated on disk.
While the stream is open, you can also use methods such as seek() o truncate() all with move the write pointer to a specific position or change the file sizeBut it's important to remember that the changes aren't permanently applied until the stream is closed.
Suggest filename and home folder to the user
The API also takes care of the user experience in system dialog boxes. For example, You can specify a suggested filename when you call showSaveFilePicker()This allows the user to see something more descriptive, such as "New Document.txt," instead of a generic "No Title".
Similarly, It is possible to suggest an initial folder where the file picker starts.This is done by passing a property startIn when you call showSaveFilePicker(), showOpenFilePicker() o showDirectoryPicker()The values can be strings like desktop, documents, downloads, music, pictures o videos, which correspond to standard system locations.
Also, you have the option of use as a value of startIn a file or directory manager that you already haveIn that case, the dialog box opens directly in the folder where that handle resides, which is very convenient for resuming the working context of the last session.
If your application handles different types of files (for example, text documents and embedded images), you can define separate IDs for each dialog type . This way, the browser will remember the last used folder independently for each ID, and you won't mix up document and image paths.
Remember recent files and folders with IndexedDB
One of the strengths of File System Access is that its handlers are serializable. This means you can store FileSystemFileHandle y FileSystemDirectoryHandle in IndexedDB and retrieve them in subsequent sessions, always respecting the permissions policy.
Thanks to this, web applications can offer typical desktop functionalities such as lists of recent files, reopening the last project, or restoring the previous working folder . You simply need to save the handles in the browser's database and read them when the app starts.
When you retrieve a stored handle, don't assume that the permissions are maintained . The browser might decide to request authorization again, for example, because time has passed or the last tab from that source has been closed. Therefore, it's recommended that your code check the situation.
For this check, The API includes the methods queryPermission() y requestPermission() both in file and directory handlersFirst, you ask what status the permission is in, and if it is not "granted", you can request it again from the user, indicating in the options whether you need read only or read and write.
A good practice is to combine both steps into a helper function that, given a handle and a mode (read-only or read/write), checks if permission is already granted and, if not, displays the corresponding prompt. This reduces the number of dialogs and makes the experience smoother.
Open and browse entire directories from the browser
In addition to individual files, the API allows working with entire folders. With showDirectoryPicker() the user can select a complete directoryand the application receives a FileSystemDirectoryHandle which gives access to all its elements.
By default you will have read permission on the files in that directory, although if you need to write to them as well You can request read and write access by passing { mode: 'readwrite' } when calling showDirectoryPicker()From that moment on, your app can list and manipulate the content according to the permission granted.
To navigate through the folder, You can iterate asynchronously over dirHandle.values()which returns, one by one, the elements it contains: files and subdirectories. Each entry has a property kind which tells you if it is a "file" or "directory".
If you need to access information about each file, such as its size, you can call entry.getFile(). In these cases, it is recommended to run the readings in parallel using Promise.all() or similar techniques, instead of going one by one in a strictly sequential manner, which can be slower.
You can also do this from a directory create new folders or files with getDirectoryHandle() y getFileHandle()You can specify in the options whether you want them to be created if they don't already exist. For example, you can set up a project structure like "My Project / Code / Notes.txt" directly from the web application.
Manage files: delete, rename, and move
The API is not limited to reading and writing. It also allows you to delete files and folders from a directory using removeEntry() over a FileSystemDirectoryHandleIf it's a folder, you can make the deletion recursive, so that it includes all its subfolders and files.
If instead of going through the directory you want to act directly on a file or folder handle, Some browsers offer this method remove() en FileSystemFileHandle y FileSystemDirectoryHandleThis way you remove that element without needing to refer to its name within the parent directory.
For organizational operations such as renaming or moving items to another folder, There is a method move() in the interface FileSystemHandleYou can directly pass it a new name, a destination directory, or a directory plus the new name to move and rename at the same time.
However, there are nuances to compatibility: the support of move() It is more mature for files within the source private file system (OPFS)and may still be behind flags or not implemented for all scenarios or for directories in certain browsers.
Drag and drop files and folders to the web
The File System Access API integrates very well with HTML's drag-and-drop system. When the user drags files or folders from the operating system to a web pagethe browser creates elements DataTransferItem associates.
Through the method DataTransferItem.getAsFileSystemHandle(), you can get a FileSystemFileHandle whether the element is a file or a FileSystemDirectoryHandle if it's a directoryThus, an app can allow the user to drag and drop an entire folder of photos and work directly on its contents.
You should keep in mind that, in the context of drag and drop, DataTransferItem.kind It will always be "file" for both files and foldersYou will obtain the distinction between file and directory by consulting the property kind of the FileSystemHandle that gives you back getAsFileSystemHandle()which will differentiate between "file" y "directory".
Private Source File System (OPFS) and optimized access
In addition to accessing the user's files and folders, Chromium browsers offer an origin private file system (OPFS) . This is a storage space dedicated to each website, not directly accessible by the user from the operating system.
In practice, this means that although the browser internally stores this data on disk, the user won't find it as "normal" files in a random folder . It could be a database, packaged files, or any internal structure the browser deems appropriate.
From the API you can access the root of this private system using navigator.storage.getDirectory(), which returns a FileSystemDirectoryHandle. From there you can create files and directories, read them, write to them, rename them or delete them just as if they were elements of the local file systemBut knowing that they are isolated and dedicated exclusively to your web application.
For more advanced performance needs, Chromium incorporates a special type of file with optimized synchronous access. Through fileHandle.createSyncAccessHandle() (available in workers), you can get a handle that allows synchronous and exclusive reading and writing, which is useful for very intensive or latency-sensitive use cases.
Obtaining the handle remains asynchronous, but once you have it, read and write operations are performed as direct calls, manipulating byte buffers . This closely approaches the performance of a native application, while remaining within the web environment and maintaining isolation from the private source system.
Polyfills and alternatives when there is no native support
Although the File System Access API offers many possibilities, not all browsers support it yet . It's not possible to create a complete polyfill that replicates all its capabilities, primarily because there's no way to reliably simulate native file system access without the browser's cooperation.
However, some parts can be approximated. To emulate showOpenFilePicker() a simple <input type="file">, which displays the file selection box and allows the user to choose one or more files.
Something similar happens with saving. To imitate showSaveFilePicker() a link is often used <a download="nombre"> Clicking it initiates the download of a Blob generated from JavaScript. This allows you to "save" data generated by the website, although it doesn't offer the option to overwrite existing files.
Regarding selecting entire directories, the non-standard attribute has traditionally been used webkitdirectory en <input type="file">which allows you to choose a folder and receive a list of the files it contains. It is not a universal solution nor as powerful as showDirectoryPicker()but it covers some cases.
To unify these approaches, libraries like browser-fs-access exist that attempt to use the modern API whenever available and, if not, automatically fall back to these better alternatives . This way, the developer writes relatively uniform code, and the library handles adapting to the environment.
Security, permissions and user control
All this power comes with responsibilities, and browser teams are well aware of this. The design of the File System Access API revolves around two principles: user control and transparency . No websites secretly reading half a hard drive.
When a user opens a file using the selection boxes (either to read or to save a new one), that action grants read or write permission to the specific file or folder . If the user changes their mind and cancels the dialog, the website receives nothing and therefore does not gain any access.
To save a new file, click the “Save” box It not only allows you to choose a name and path, but also serves as a grant of write permission on that newly created file.The logic is the same as that used for years in elements such as <input type="file">but extended with more capabilities.
When a web application wants to modify an existing file, it cannot simply do so; the browser may display a specific prompt requesting permission to write to it . This dialog box can only be opened in response to a user action, such as clicking a "Save Changes" button.
If the user decides not to grant write permission, the website must offer an alternative: downloading a copy, saving to the cloud, working in OPFS, or another similar mechanism . The idea is that the user always has the final say on what is changed on their local system.
For transparency, browsers display an icon in the address bar when a website has access to local files . If the user clicks on this icon, they will see a list of the files or folders the page currently has access to and can revoke permissions at any time.
Permissions are not permanent. Generally, a website retains the ability to save files only as long as at least one tab from that source is open . Once all tabs are closed, the browser may consider the session to be over, and the next time you use it, you will need to request permission again for those files or directories.
Combining the file:/// scheme to open specific resources, keyboard shortcuts to load local files, and the File System Access API for deep integrations makes the browser a much more versatile tool for both users and developers , allowing them to quickly view a video saved on disk or edit entire projects without leaving the web environment.
Passionate writer about the world of bytes and technology in general. I love sharing my knowledge through writing, and that's what I'll do on this blog, show you all the most interesting things about gadgets, software, hardware, tech trends, and more. My goal is to help you navigate the digital world in a simple and entertaining way.