SQLite database resets after every deploy: why production data disappears

Short answer

SQLite keeps the whole database in one file on the server's disk, and most hosts don't keep that disk. Fix: Stop shipping the database file with your code; On Vercel, Netlify or Cloudflare Pages, move to a hosted database; Using Prisma? Point it at the new database; Keeping SQLite? Put the file on a Railway volume; On Render or Fly.io, use a disk or volume; Back up the file somewhere else.

You'll see:
  • New sign-ups, posts or orders vanish after a redeploy, a restart or an idle spin-down
  • Production shows your local test data again after every push
  • On Vercel, writing the .db file fails with a read-only file system error

Why does this happen?

SQLite keeps the whole database in one file on the server's disk, and most hosts don't keep that disk. Vercel Functions get a read-only filesystem with only temporary /tmp scratch space, and separate instances don't share storage. Container hosts such as Railway, Render and Fly.io start each deploy on a fresh, ephemeral filesystem unless you attach a volume or disk. And if the .db file is committed to Git, each deploy ships your local copy over whatever production had.

How do you fix it?

  1. Stop shipping the database file with your code

    Add the database file to .gitignore and remove it from the repository (this keeps your local copy). Otherwise every push replaces production data with your laptop's test data, even on a host with persistent storage.

    echo "*.db" >> .gitignore
    echo "*.db-journal" >> .gitignore
    git rm --cached path/to/your.db
    git commit -m "Stop committing the SQLite database"
  2. On Vercel, Netlify or Cloudflare Pages, move to a hosted database

    Vercel says SQLite can't be used there because storage is ephemeral with serverless functions, and points to other storage options. Netlify and Cloudflare Pages also run server code as functions, not an always-on server (see their host pages), so plan on a hosted database there too. Turso is SQLite-compatible (libSQL) if you want to keep SQL close to what you have; Supabase and Neon are Postgres. The table below has their free tiers.

  3. Using Prisma? Point it at the new database

    Prisma supports local SQLite files, Turso (libSQL) and Cloudflare D1 with the sqlite provider: Turso uses a libsql:// URL instead of file:./dev.db. Moving to Supabase or Neon means switching the provider to postgresql and creating a fresh migration, then copying any data you need to keep.

    // prisma/schema.prisma
    datasource db {
      provider = "postgresql" // was "sqlite"
    }
  4. Keeping SQLite? Put the file on a Railway volume

    Attach a volume and write the database inside its mount path. Railway's example: if your app writes to ./data, mount the volume at /app/data. Railway also sets RAILWAY_VOLUME_MOUNT_PATH at runtime. Volumes are mounted when the container starts, not during the build or pre-deploy step, so create and migrate the database in the start command. If your image runs as a non-root user, Railway says to set RAILWAY_RUN_UID=0.

    // db path that works locally and on a Railway volume
    import path from "node:path";
    const dir = process.env.RAILWAY_VOLUME_MOUNT_PATH ?? "./data";
    const dbFile = path.join(dir, "app.db");
  5. On Render or Fly.io, use a disk or volume

    Render: Free web services have an ephemeral filesystem, so local SQLite databases are lost on every redeploy, restart or spin-down. Persistent disks attach only to paid services, and only files under the disk's mount path survive. Fly.io: a Machine's root filesystem is ephemeral, so keep the database on a Fly Volume. Render's other option is Render Postgres, but Free Render Postgres databases expire 30 days after creation.

  6. Back up the file somewhere else

    A volume keeps data across deploys, but it is not a backup. Railway's SQLite template page recommends exporting or copying the database file on a schedule and keeping the copy somewhere else.

Hosted databases you can move to

Hosted database free tiers and entry prices
Database Type Free tier Paid from
Turso (opens in a new tab) SQLite-compatible (libSQL) database Free: 100 databases, 5 GB storage, 500M rows read and 10M rows written per month $5.99/mo (checked 17 Oct 2026)
Supabase (opens in a new tab) Postgres + auth + storage + realtime Free: 500 MB database, 50,000 MAU, 5 GB egress, 1 GB file storage, 2 active projects $25/mo (checked 17 Oct 2026)
Neon (opens in a new tab) Serverless Postgres (scale to zero) Free: 100 projects, 100 CU-hours per project/month, 1 GB storage per project (20 GB total) Usage-based, no minimum (checked 17 Oct 2026)

Full limits and catches: free-tier details.

Common questions

Can I keep the SQLite file in `/tmp` on Vercel?

Vercel gives functions writable /tmp scratch space up to 500 MB, but it is temporary and not shared between function instances, so it can't act as your database.

Does Render's free plan keep my SQLite file?

No. Render says Free web services lose local files, including SQLite databases, whenever they redeploy, restart or spin down, and Free services can't attach a persistent disk.

Is Turso a drop-in replacement for SQLite?

Turso is SQLite-compatible (libSQL), and Prisma connects to it with the same sqlite provider and a libsql:// URL. Your app talks to it over the network instead of opening a local file, so the connection code changes.

Why did my data come back as old test data after a deploy?

The .db file is in your Git repository, so each deploy copies your local version over the server's file. Remove it from Git (step 1) and keep production data in a volume or a hosted database.

Common with:

Related fixes