Logo for tanaschita.com

Working with files and directories in iOS

Understanding the app sandbox and how to access system directories.

06 Apr 2026 · 6 min read

When developing an iOS app, we often need to persist data that doesn't naturally fit into a database or UserDefaults. This can include images, exported files, cached responses, or other user-generated content.

iOS provides a well-defined structure for storing files inside an app’s sandbox. Understanding how these directories work, and how to interact with them, allows us to build predictable and maintainable file handling into our apps.

Let's jump in.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

Understanding the app sandbox

Each iOS app operates within its own sandbox directory. For security reasons, our app can only access files inside this container, unless explicit permission is granted (for example when accessing photos or documents).

The sandbox is divided into two main areas:

Bundle container

Contains the app bundle (.app) with all bundled resources such as images, localization files, or JSON files. This directory is read-only at runtime.

Data container

Contains all files created and managed by the app. This is where we read and write data during runtime.

Inside the data container, there are three important directories:

  • Documents: Used for user-generated content.
  • Library: Used for app-specific data that should not be directly exposed to the user.
  • tmp: Used for temporary files that can be deleted by the system at any time.

Let's take a closer look at the most relevant directories.

The Documents directory

The Documents directory is intended for user-generated content. This includes anything a user might create, edit, or explicitly interact with, such as images, videos, or exported files.

We can freely create subdirectories here to organize content.

The system also provides a Documents/Inbox directory, which is used when other apps hand over files to our app. Files in this directory can be read and deleted, but not modified in place.

The Library directory

The Library directory contains data used internally by the app. The most relevant subdirectories are:

  • Library/Application Support: Used for files the app needs to function, such as configuration files or stored data that should not be visible to the user.
  • Library/Caches: Used for cached data that can be recreated if needed. The system may remove these files to free up disk space.

Accessing directories

So far, we’ve looked at where files live inside the app sandbox. The next step is accessing these locations in code.

In iOS, file locations are represented by URL. Instead of working with string paths, we use these URLs as references to files and directories. We can access common directories directly through URL:

let documentsURL = URL.documentsDirectory
let cachesURL = URL.cachesDirectory
let applicationSupportURL = URL.applicationSupportDirectory

These URLs point to the corresponding locations inside our app's data container. Under the hood, these values are resolved using FileManager. If we need more control, we can fall back to:

let directoryURL = try FileManager.default.url(
for: .applicationSupportDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false
)

In most cases, however, the URL APIs are sufficient and keep the code more concise.

Reading and writing files

Once we have a directory URL, we can create a file URL by appending a file name, and then use it to read or write data.

let fileURL = directoryURL.appendingPathComponent("fileName.json")

To write data:

try data.write(to: fileURL)

To read data:

let data = try Data(contentsOf: fileURL)

Creating directories

We can create custom subdirectories to organize files:

let customDirectoryURL = directoryURL.appendingPathComponent("directoryName")
try FileManager.default.createDirectory(
at: customDirectoryURL,
withIntermediateDirectories: false,
attributes: nil
)

If the directory already exists, this call will throw an error. In practice, we either check beforehand using fileExists(atPath:) or handle the error accordingly.

Accessing bundled resources

So far, we've only looked at files that are created and managed by our app at runtime.

In addition to that, we often need to read files that are shipped with the app, such as configuration files or sample data. These files live in the app bundle, which is part of the read-only bundle container.

To access them, we can use the Bundle type:

let url = Bundle.main.url(forResource: "nameOfTheResource", withExtension: "json")

Once we have the file URL, we can read it just like any other file:

let data = try Data(contentsOf: url)
let configuration = try jsonDecoder.decode(Configuration.self, from: data)

The key difference is that bundled resources are read-only, while files in the data container can be both read and written.

Managing file backups

By default, files stored in the Documents directory and in Library/Application Support are included in iCloud backups.

In some cases, this is not what we want. For example, cached or downloadable data can be recreated and does not need to be backed up.

To control this behavior, we can attach metadata to a file URL.

In iOS, file URLs can store additional resource values that describe how the system should treat a file. One of these values determines whether a file is included in backups.

We can update this value using URLResourceValues:

var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
try url.setResourceValues(resourceValues)

By setting isExcludedFromBackup to true, we tell the system that the file should not be included in iCloud backups.

This is especially useful for files in the Caches directory or any data that can be recreated if needed.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

swift

persistence

ios

Storing Swift structs in UserDefaults

Why Codable works but often isn't the best choice.

05 Jan 2026 · 4 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum