Persistent Filesystems

Apps on Plotly Cloud don’t persist files between runs by default. Anything an app writes to while it’s running, such as datasets, uploaded files, or saved results, is lost when the app restarts, when you publish a new revision, or when the app goes to sleep.

A persistent filesystem gives your app durable storage that it uses like a regular folder. Start by creating a persistent filesystem for your team and attach it to an app at a mount path, such as /data. Then use that path when writing, editing, or deleting files within your app. Files stored in this location persist across restarts and can be accessed centrally by one or more apps on Plotly Cloud.

Persistent filesystems are available on Pro and Enterprise plans.

How Persistent Filesystems Work

Persistent filesystems belong to your team, not to a single app. You can attach a persistent filesystem to as many of your team’s apps as you like, and they can all use it at the same time. This is useful when one app keeps its own state, and also when several apps need the same large dataset or model file. For example, one app can refresh a dataset on the persistent filesystem while other apps read it.

There’s no size to choose when you create a persistent filesystem, and you never need to resize one. Your team pays only for the data that you store. See Storage Usage and Billing.

Every Creator on the team can manage every persistent filesystem, and any app on the team can have a persistent filesystem attached with full read and write access. There are no permissions for individual persistent filesystems, so don’t store data on a persistent filesystem that only some team members should see. Keep secrets such as passwords and API keys in environment variables.

Creating a Persistent Filesystem

Only team members with the Creator role can create persistent filesystems.

To create a persistent filesystem:

  1. Go to Plotly Cloud: https://cloud.plotly.com/
  2. In the sidebar, select Persistent filesystems.
  3. Select Create persistent filesystem.
  4. Enter a name for the persistent filesystem, such as shared-datasets. Names can be up to 63 characters and must be unique within your team.
  5. Select New persistent filesystem.

The new persistent filesystem appears in the table with the Setting up status while Plotly Cloud sets it up. When the status changes to Ready, apps can use it.

You can also create a persistent filesystem at publishing time, or from within an app’s settings.

Attaching a Persistent Filesystem to an App

When you attach a persistent filesystem, you choose the mount path where it appears inside your app. The app’s code can then read and write files under that path.

To attach a persistent filesystem to an app:

  1. Go to your app Settings <img>.
  2. Go to the Persistent filesystems tab.
  3. Select Attach persistent filesystem.
  4. In Persistent filesystem, select an existing persistent filesystem, or select Create new… to create one.
  5. In Mount path, enter the path where the persistent filesystem should appear in your app, such as /data.
  6. Select Attach.

Attaching or detaching a persistent filesystem restarts your app’s running instances. You don’t need to publish a new revision.

If you attach a persistent filesystem that’s still being set up, it appears in the list as (setting up). The app restarts again and the persistent filesystem is mounted when its status changes to Ready. Until then, nothing is available at the mount path.

Attaching a Persistent Filesystem When Publishing a New App

When you publish a new app from the Cloud UI, the Storage section asks Will this app save files while running?

Choosing a Mount Path

The mount path must be an absolute path, such as /data or /mnt/uploads. It can’t contain . or .. segments or end with a /. The directory doesn’t need to exist in your app files, because Plotly Cloud creates it.

You can’t mount a persistent filesystem at a system path or anywhere under one. The reserved paths are /, /app, /bin, /boot, /dev, /etc, /home, /lib, /lib64, /proc, /root, /run, /sbin, /secrets, /sys, /tmp, /usr, and /var.

An app can have more than one persistent filesystem attached, but each one needs its own mount path. Two mount paths in the same app can’t be identical, and one can’t be inside the other. For example, you can’t mount one persistent filesystem at /data and another at /data/models.

Using a Persistent Filesystem in Your App

Your app uses the mount path like any other directory. To keep the same code working locally and on Plotly Cloud, read the path from an environment variable and fall back to a local folder when the variable isn’t set. In this example, set DATA_DIR=/data on Plotly Cloud:

import os
from pathlib import Path

DATA_DIR = Path(os.environ.get("DATA_DIR", "./data"))
DATA_DIR.mkdir(parents=True, exist_ok=True)

def save_upload(filename, content):
    (DATA_DIR / "uploads").mkdir(exist_ok=True)
    (DATA_DIR / "uploads" / filename).write_bytes(content)

Only write files that need to persist to the persistent filesystem. Temporary files that your app can recreate are better kept in a local directory such as /tmp.

Sharing Files Across Apps

Several apps can write to the same persistent filesystem at the same time. File locks on a persistent filesystem are advisory, so if two apps write to the same file, the apps themselves need to coordinate those writes. The simplest approach is to give each app its own folder, or to have a single app write a file that the other apps only read.

Using SQLite

You can store a SQLite database on a persistent filesystem. Persistent filesystems on Plotly Cloud are network filesystems (Amazon EFS), so SQLite needs different settings than it does on a local disk.

Open every connection with the journal mode set to DELETE:

import os
import sqlite3
from pathlib import Path

DATA_DIR = Path(os.environ.get("DATA_DIR", "./data"))
DB_PATH = DATA_DIR / "app.db"

def get_connection():
    conn = sqlite3.connect(DB_PATH, timeout=10)
    conn.execute("PRAGMA journal_mode=DELETE")
    return conn

Don’t use write-ahead logging (PRAGMA journal_mode=WAL), even if only one app uses the database. WAL mode requires every connection to the database to be on the same machine. When your app restarts, for example when you publish a new revision, change a setting, or attach a persistent filesystem, Plotly Cloud starts the new instance of your app before it stops the old one. For a short time, both instances have the database open, and they can be on different machines. If the database is in WAL mode during this overlap, the database file can become corrupted. DELETE mode works on both network filesystems and local disks, so you can use the same code locally and on Plotly Cloud.

The timeout argument sets how many seconds a connection waits for another connection to finish writing before it raises a database is locked error. Python’s sqlite3 module waits 5 seconds by default. If your app sees database is locked errors, increase the timeout.

SQLite allows only one writer at a time. Multiple workers in a single app can share a database. If several apps need to write to the same data, or your app writes very frequently, use a hosted database such as PostgreSQL instead, and store its connection string in an environment variable. For more information, see Plotly Cloud IP Addresses.

Moving an Existing Database out of WAL Mode

The journal mode is stored in the database file. A database that was created in WAL mode stays in WAL mode until you change it, including when you copy the file to a persistent filesystem. To convert a database file before you copy it, run the following command where the file is stored locally:

sqlite3 app.db "PRAGMA journal_mode=DELETE;"

SQLite can only leave WAL mode when no other connection has the database open. If a database on a persistent filesystem is already in WAL mode, stop every app that uses it, and then start a single app that opens the database with PRAGMA journal_mode=DELETE, as in the get_connection example. If the statement fails with database is locked, another connection still has the database open. Alternatively, start over with a new database file.

Recognizing a Corrupted Database

The errors file is not a database and database disk image is malformed mean that the database file is corrupted. Retrying the query won’t fix them. Run PRAGMA integrity_check to see the extent of the damage. Persistent filesystems don’t have backups or snapshots, so keep your own exports of any data that you can’t recreate.

Using diskcache

The diskcache library, which Dash apps often use for background callbacks and caching, stores its index in a SQLite database that uses WAL mode by default. A cache usually doesn’t need to persist, so keep the cache directory in your app’s local storage, such as ./cache. If you do need to keep a cache on a persistent filesystem, turn off WAL mode and memory mapping when you create the cache:

import diskcache

cache = diskcache.Cache(
    "/data/cache",
    sqlite_journal_mode="delete",
    sqlite_mmap_size=0,
)

Storage Usage and Billing

The Persistent filesystems page shows Storage used, which is the total amount of data stored across all of your team’s persistent filesystems. Plotly Cloud measures storage every 15 minutes, and each measurement appears after a short delay, so a new persistent filesystem shows Not measured yet until its first measurement.

Storage draws from the same shared credit balance that your team uses for compute. You pay for the data that’s stored, not for a provisioned size, and when you delete a persistent filesystem, its data stops counting toward your bill. For current rates, see https://plotly.com/pricing.

Detaching a Persistent Filesystem

Detaching a persistent filesystem removes it from an app. The files stay on the persistent filesystem, and other apps that have it attached aren’t affected.

To detach a persistent filesystem:

  1. Go to your app Settings <img>.
  2. Go to the Persistent filesystems tab.
  3. Next to the persistent filesystem, open the actions menu and select Detach.
  4. In the confirmation dialog, select Detach.

The app restarts to apply the change.

Deleting a Persistent Filesystem

Deleting a persistent filesystem permanently removes all of its files. This can’t be undone.

You can’t delete a persistent filesystem while it’s attached to apps. Detach it from all apps first. The Attached apps column on the Persistent filesystems page shows which apps use each persistent filesystem.

To delete a persistent filesystem:

  1. In the sidebar, select Persistent filesystems.
  2. Next to the persistent filesystem, open the actions menu and select Delete.
  3. In the confirmation dialog, select Delete.

The persistent filesystem shows the Deleting status while Plotly Cloud removes its files.

Limitations

Keep the following limitations in mind when you plan how your app uses a persistent filesystem: