# platformdirs decides where a Python app should store data on macOS, Windows, Linux and iOS

> platformdirs is a small MIT licensed Python package that returns the correct directory for user data, config, cache, state, logs and runtime files on each operating system, with both string and pathlib.Path variants. It is a dependency of a wide kind of tooling, and its value is the set of platform rules you would otherwise have to rediscover.

**tox-dev/platformdirs** —  A Python package for determining platform-specific directories (e.g. user data, config, cache, logs). Handles the differences between macOS, Windows, Linux/Unix, and Android so you don't have to.

- Repository: https://github.com/tox-dev/platformdirs
- Website: https://platformdirs.readthedocs.io
- Stars: 995 · Forks: 113
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/tox-dev-platformdirs

## The problem is that every platform names the same concept differently

Every operating system has an opinion about where an application should keep its files, and none of them agree. Linux follows the XDG base directory specification, macOS has a convention around Application Support and Preferences, Windows uses AppData under the user profile, and mobile platforms add their own constraints.

The consequence for a Python developer is that the code that writes a config file becomes a pile of os.path.join calls and sys.platform checks, and it is code that has to be tested on every platform it claims to support, or at least believed about.

platformdirs removes that. The package is described as determining platform-specific directories such as user data, config, cache and logs, handling the differences between macOS, Windows, Linux and Unix, Android and iOS so that you do not have to. It lives under the tox-dev organisation, which is a hint about its role: it is the kind of low-level utility that test runners and packaging tools depend on rather than the kind of library an application installs deliberately.

The package is MIT licensed, requires Python 3.11 or newer, and is classified as a Production/Stable library with support for CPython and PyPy across Python 3.11 through 3.15.

## PlatformDirs gives you a directory per concept, not per platform

The central class is PlatformDirs, constructed with an application name and an optional application author:

```python
from platformdirs import PlatformDirs

dirs = PlatformDirs("MyApp", "MyCompany")
dirs.user_data_dir  # ~/.local/share/MyApp (Linux)
dirs.user_config_dir  # ~/.config/MyApp (Linux)
dirs.user_cache_dir  # ~/.cache/MyApp (Linux)
dirs.user_state_dir  # ~/.local/state/MyApp (Linux)
dirs.user_log_dir  # ~/.local/state/MyApp/log (Linux)
dirs.user_documents_dir  # ~/Documents
dirs.user_downloads_dir  # ~/Downloads
dirs.user_runtime_dir  # /run/user/<uid>/MyApp (Linux)
```

The examples are Linux paths, but the object resolves to the right location on whichever platform it is running on. The application name scopes the path, and the author argument is what macOS uses to separate an app by its developer in the Application Support tree.

The same object exposes pathlib.Path variants, which is the part worth noticing because mixing strings and Paths is a common source of bugs when a value ends up being passed to something that expects one or the other:

```python
from platformdirs import PlatformDirs

dirs = PlatformDirs("MyApp", "MyCompany")
dirs.user_data_path  # pathlib.Path('~/.local/share/MyApp')
dirs.user_config_path  # pathlib.Path('~/.config/MyApp')
```

And for the cases where you do not want an object at all, there are module-level convenience functions, where the trailing part of the name tells you the return type:

```python
from platformdirs import user_data_dir, user_config_path

user_data_dir("MyApp", "MyCompany")  # returns str
user_config_path("MyApp", "MyCompany")  # returns pathlib.Path
```

## Data, config, state and cache are not interchangeable

The taxonomy of directory types is the substance of the package, and it is finer than most hand-rolled implementations manage.

Application directories come in user_ and site_ variants, per-user writable and system-wide read-only, where applicable. The application-scoped types are data for persistent application data, config for configuration files and settings, preference for user preferences which is distinct from config on macOS, cache for data that can be regenerated, state for non-essential runtime state such as window positions, logs for log files, and runtime for runtime files such as sockets and PIDs.

The distinction that catches people out is state versus cache. The package documentation describes cache as data that can be regenerated and state as non-essential runtime state, and those two have different rules about whether a user or an operating system may delete them. Code that stores something the user would miss in the cache directory loses it.

Then there are the user media directories, which are the standard folders on the machine and are not scoped by the app name: documents, downloads, pictures, videos, music, desktop, projects, public share, templates, fonts, executable and applications. The fonts entry is called out as the user-writable font installation directory, and the executable and applications entries come in user_ and site_ forms.

The naming convention itself is worth internalising: the prefix tells you the scope, and the suffix tells you the category. A property that does not exist for your platform simply is not there, rather than returning a wrong path.

## Installing it and printing the resolved paths

The package is published on PyPI as platformdirs and requires Python 3.11 or newer. The project documentation does not give an install command, so take the name platformdirs from PyPI and add it to your project's dependencies the way you manage the rest of them.

A first real use is a single import and one constructor call, and the point of the exercise is to see the paths on the machine you are actually on rather than the Linux examples in the documentation:

```python
from platformdirs import PlatformDirs

dirs = PlatformDirs("MyApp", "MyCompany")
dirs.user_data_dir  # ~/.local/share/MyApp (Linux)
dirs.user_config_dir  # ~/.config/MyApp (Linux)
dirs.user_cache_dir  # ~/.cache/MyApp (Linux)
```

On Linux you should see the XDG-shaped paths, on macOS the Application Support and Preferences locations, and on Windows the AppData locations. If the output surprises you, the reason is usually an environment variable overriding the platform default, which is worth knowing before you go looking for a bug in your own code.

The package also ships a pytest plugin, registered through the entry point in pyproject.toml as platformdirs.pytest_plugin. That means the plugin is available automatically in a test session without a conftest.py change, which is convenient if you want to assert on resolved paths in your own test suite.

The project publishes its documentation at platformdirs.readthedocs.io, with a getting started tutorial, how-to guides, an API reference and a page listing the default paths for each operating system. That last page is the one to keep open when you are trying to work out why a path on a machine you do not own is not what you expected.

## The appdirs lineage, and what platformdirs does not decide for you

The package keywords include appdirs, and the lineage is worth knowing because a lot of code in the wild still depends on the older name. platformdirs is the successor to appdirs, and projects that depend on appdirs today are usually pulling in something that re-exports a similar API. If you are reading a project and see an appdirs import, check whether it is the original or a shim before assuming behaviour.

What platformdirs deliberately does not do is create the directories. The API returns paths; it does not mkdir them. The documentation does not describe any creation side effect, and a library that silently created directories as a side effect of a property lookup would be unpleasant to use, since merely asking where the log file goes would litter the filesystem. The consequence is that your code still has to make the directory before writing to it.

It also does not decide what goes where for you. The taxonomy is a vocabulary, and choosing between config and state, or between data and cache, is a domain decision the library cannot make. The documentation groups the types, but the semantics of your application decide the placement.

Finally, there is no mechanism for reading or writing config files. platformdirs gives you a location; parsing TOML, YAML or INI and merging with defaults is the job of another library. Several projects in the tox-dev organisation handle that layer, and the boundary between them is a reasonable division of labour.

## A small package with a rapid release cadence and a public API to keep stable

The repository is small and focused. At the top level there are src/, tests/, docs/, a pyproject.toml, a tox.toml, a pre-commit configuration, a readthedocs configuration and the usual repository files.

The build system is hatchling with hatch-vcs, which means the version is derived from the version control tags rather than written by hand, and the pyproject.toml lists the version as dynamic. The project requires-python is 3.11 or newer, and the classifiers cover Python 3.11 through 3.15, CPython and PyPy, with the OS Independent marker.

Maintenance is current. The repository is not archived, the last push was on 2026-10-19, and the three most recent releases are 4.13.5 on 2026-10-19, 4.13.4 on 2026-10-17 and 4.13.3 on 2026-10-16. That is a patch release every couple of days, which fits a package that sits under many other tools and has to keep working across new Python versions and new platform conventions.

The cost of that cadence is on the consumer. Since a large number of downstream projects depend on platformdirs, a release here can propagate into a long chain of lock files and rebuilds, and the four named maintainers in the pyproject.toml indicate the project is maintained by a small group rather than a single author.

The licence is MIT, declared in the pyproject.toml and paired with a LICENSE file at the repository root. That is a permissive licence with no copyleft obligations, which is the expected choice for a package this widely embedded, and there is nothing licence-wise here that would give a downstream project pause.

## Conclusion

platformdirs fits any Python application that persists anything, from a CLI that keeps a config file to a desktop app that writes a cache, and it fits build and packaging tools that need to place files where the platform expects them. It does not fit an application with a fixed deployment layout, such as a container that mounts its own volumes, where the XDG variables override the platform defaults and make the returned path a fiction. Before adopting it, check that the directory you pick is one of the documented types, since cache and state have different deletion semantics, and note that the package requires Python 3.11 or newer.

## FAQ

### What is platformdirs and what does it solve?

platformdirs is a Python package for determining platform-specific directories such as user data, config, cache and logs. It handles the differences between macOS, Windows, Linux and Unix, Android and iOS, so application code does not have to carry per-platform path logic.

### How do I install platformdirs and get a config directory?

Install it with `pip install platformdirs`, then construct `PlatformDirs("MyApp", "MyCompany")` and read `user_config_dir` for a string path or `user_config_path` for a pathlib.Path. Convenience functions such as user_data_dir and user_config_path are available for one-off lookups.

### What is the difference between user_data_dir, user_cache_dir and user_state_dir?

Data is persistent application data, cache is data that can be regenerated, and state is non-essential runtime state such as window positions. The distinction matters because cache and state have different deletion semantics, so data that matters should not be written to the cache directory.

### Does platformdirs create the directories it returns?

The API returns paths and does not document creating them, so your code needs to make the directory before writing to it. The package also ships a pytest plugin registered as platformdirs.pytest_plugin, which is available in test sessions without a conftest.py change.

## Sources

- [License: MIT](https://github.com/tox-dev/platformdirs/blob/main/LICENSE)
- [Project website](https://platformdirs.readthedocs.io)
- [README](https://github.com/tox-dev/platformdirs/blob/main/README.md)
- [Releases](https://github.com/tox-dev/platformdirs/releases)
- [tox-dev/platformdirs on GitHub](https://github.com/tox-dev/platformdirs)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tox-dev-platformdirs
