# Where an App Keeps Its Data

An app keeps its data in ~/.local/share and its settings in ~/.config, whatever folder you run it from, makes those folders and files itself on its first run, and loads its settings file with source.

Journeyman · Unix · Linux · Updated November 10, 2026

## After this lesson you can

- Keep an app's data in ~/.local/share and its settings in ~/.config, using ${XDG_DATA_HOME:-$HOME/.local/share} for the folder
- Create an app's folders and files on its first run with mkdir -p, and load its settings from a config file with source

## Key takeaways

- A file name with no folder, such as recipes.txt, is looked for in the folder you're in. An app's data needs a fixed place instead.
- On Linux, apps keep settings in ~/.config/APP and data in ~/.local/share/APP. ${XDG_DATA_HOME:-$HOME/.local/share} uses a person's own choice when they've set one.
- On its first run, an app makes what's missing with mkdir -p and touch, and writes a config file with the default settings.
- source runs a config file's lines, so its settings become variables. Only source a file that you alone can change.

Your browser remembers your bookmarks, and a music app remembers your playlists, whichever folder you happen to be in when you open them. Your recipe box doesn't, yet. Go to your home folder and ask it for the list:

```bash
cd ~
terminal-practice/recipe-app/recipes list
```

```text
terminal-practice/recipe-app/recipes: line 26: recipes.txt: No such file or directory
```

`recipes.txt` is a name with no folder, so the script looks for it in the folder you're standing in. That worked only while you stood next to it. A real app keeps its data in one fixed place, and every app on the computer agrees where.

## Two hidden folders in your home

Your home folder has two hidden folders for this, the way a house has a closet for coats and a shelf for keepsakes:

- `~/.config` holds **configuration files**: settings a person may want to change, such as how many minutes count as "quick". `git`, for one, reads settings from `~/.config/git`.
- `~/.local/share` holds data: what the app collects as you use it, such as your recipes.

![Sam's home folder drawn as a tree. Inside it, the hidden folder .config holds recipes/config, labeled "settings: what a person may change", and the hidden folder .local holds share/recipes/recipes.txt, labeled "data: what the app collects". The recipes app, run from any folder, points at both](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/11/c8311ddb126b4bb0a55be1de6a368b9c.webp)

Each app gets a folder of its own inside them: `~/.config/recipes` and `~/.local/share/recipes`. The dot at the start of each name keeps them out of a plain `ls`. These places come from a short set of rules most Linux apps follow, the **XDG Base Directory** rules (XDG is a group that writes shared rules for Linux desktops). Mac apps with windows keep their data in `~/Library/Application Support`, but command-line tools such as `git` look in `~/.config` on a Mac too, so the lines below work there as well.

A few people move these folders, by setting `XDG_CONFIG_HOME` or `XDG_DATA_HOME`. `${XDG_DATA_HOME:-$HOME/.local/share}` (read "XDG_DATA_HOME, or if that's empty, $HOME/.local/share") respects that, with the default from *Asking Questions: read*. It says `$HOME`, not `~`, because a `~` inside quotes stays a plain `~`.

## The first run makes what's missing

Open `recipes` and add these lines under its comment line:

```bash
data_dir="${XDG_DATA_HOME:-$HOME/.local/share}/recipes"
data_file="$data_dir/recipes.txt"
config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/recipes"
config_file="$config_dir/config"

# The first run makes the app's folders and files.
if [[ ! -f "$data_file" ]]; then
  mkdir -p "$data_dir"
  touch "$data_file"
fi
if [[ ! -f "$config_file" ]]; then
  mkdir -p "$config_dir"
  printf '# Settings for recipes\nquick_minutes=30\n' > "$config_file"
fi
source "$config_file"
```

Then make four small changes further down:

1. Write `"$data_file"` in place of `recipes.txt`, in `cmd_add` and at the end of `cmd_list`.
2. In `cmd_list`, write `"$quick_minutes"` in place of `30`.
3. In `cmd_list`, right after the getopts loop's `done`, add a friendly answer for an empty box:

   ```bash
   if [[ ! -s "$data_file" ]]; then
     echo 'Your recipe box is empty. Add one with: recipes add MINUTES CATEGORY "NAME"'
     return
   fi
   ```

4. Make the version `recipes 1.2.0`.

Now run it, look at what it made, and copy your recipes into their new home (this replaces the new, empty `recipes.txt`):

```bash
cd ~/terminal-practice/recipe-app
./recipes list
ls ~/.local/share/recipes
cat ~/.config/recipes/config
cp recipes.txt ~/.local/share/recipes/
```

```text
Your recipe box is empty. Add one with: recipes add MINUTES CATEGORY "NAME"
recipes.txt
# Settings for recipes
quick_minutes=30
```

## A config file you can change

`source`, from *Startup Files: .bashrc, .zshrc and source*, runs the config file's lines inside the script, so `quick_minutes=30` becomes a variable. Open the file with `nano ~/.config/recipes/config`, change 30 to 15, save, and ask again, this time from your home folder:

```bash
cd ~
terminal-practice/recipe-app/recipes list -q
```

```text
Overnight Oats (5 min, breakfast)
Blueberry Pancakes (15 min, breakfast)
Grilled Cheese (10 min, lunch)
```

The app now works from anywhere and remembers your setting. Because `source` runs every line as a command, keep this habit: source only a config file in your own home that only you can change.

## Try a first run safely

To see a first run again without touching your real files, give one run a pretend home, the `NAME=value command` trick from *Environment Variables: export and env*:

```bash
cd ~/terminal-practice/recipe-app
HOME=/tmp/pretend-home ./recipes list
ls -A /tmp/pretend-home
```

```text
Your recipe box is empty. Add one with: recipes add MINUTES CATEGORY "NAME"
.config  .local
```

That's how tests check an app's first run. When you're done with the recipe box, `rm -r ~/.local/share/recipes ~/.config/recipes` removes its files, and your recipes with them, for good.

## Check yourself

2 questions to try on the lesson page.

## So what

An app that keeps its data in `~/.local/share` and its settings in `~/.config` works from any folder, sets itself up on the first run, and lets people change it without touching its code.

## Key terms

- [XDG Base Directory](https://www.ask-codey.com/glossary/xdg-base-directory)
- [Configuration File](https://www.ask-codey.com/glossary/configuration-file)
- [Hidden File](https://www.ask-codey.com/glossary/hidden-file)
- [source](https://www.ask-codey.com/glossary/source-unix)

## Cheat sheets

- [Where an App Keeps Its Data](https://www.ask-codey.com/cheat-sheets/bash-app-data-and-config-cheat-sheet)

## Related

- [Subcommands: app add, app list](https://www.ask-codey.com/lessons/bash-subcommands)
- [Startup Files: .bashrc, .zshrc and source](https://www.ask-codey.com/lessons/bash-startup-files)
- [Asking Questions: read](https://www.ask-codey.com/lessons/bash-reading-input)
- [Environment Variables: export and env](https://www.ask-codey.com/lessons/bash-environment-variables)

Source: https://www.ask-codey.com/lessons/bash-app-data-and-config
