When something breaks
SQLite data lost on deploy: where to keep the database file
In short
A SQLite database is lost on deploy because the project is rebuilt from the files you uploaded, so anything the app wrote next to the code goes back to its original state. To keep the database between deploys, the file has to live in persistent storage, which on Netrun is the /data folder, and the path to it should come from an environment variable instead of being hard-coded. The database then survives code updates and restarts, and you can view and download the file on the "Data" tab. Projects that come with their own docker-compose have no /data folder, and there persistent storage means the named volumes from your file.
It usually goes like this: you change a couple of lines, upload the new version, and the app is empty. Registered users, saved orders, collected stats: everything that lived in the SQLite file is gone. It looks like the hosting broke, but nothing did. Every deploy rebuilds the project from the files you uploaded, so anything the app wrote next to the code goes back to the state it was in when you uploaded it.
Any platform that rebuilds a project from uploaded code works this way, so only storage that was made persistent on purpose stays. On Netrun that is the /data folder: whatever your app writes there survives code updates and restarts, and the files are listed on the "Data" tab, where you can download them or upload them back. The rest of this guide covers how to move a SQLite database there, and when it is time to swap SQLite for a real database.
Confirm the data disappears exactly on deploy#
The timing gives it away: the data vanishes at the moment a new version goes out or the project restarts, and holds up fine in between. Check where the database file is created: if the path is just a file name like app.db or db.sqlite3, the file sits next to your code and lives only until the next build. If your app creates the database and runs migrations at startup, you will not even notice the swap, because the database is simply new and empty every time.
Move the database path into an environment variable#
Do not hard-code the path: with a variable the same app runs both on your machine and on the server. Add something like DATABASE_PATH or DATABASE_URL, read it at startup, and fall back to a local file when the variable is missing. During project setup Netrun asks for these values and passes them in, so you do not have to edit code before every deploy.
Put the database file in the persistent /data folder#
Point the variable at a path inside the persistent folder, for example /data/app.db. Nothing needs to be created up front: the folder is already there and your app creates the file itself on first run. From that point on the data survives code updates and restarts, and the project link stays the same.
Declare a named volume if the project ships its own docker-compose#
Projects whose services you describe in your own docker-compose file have no /data folder, so there you define persistent storage yourself with named volumes. Mount a volume at the folder that holds the database and point the file path inside it. If several services write to the same file, that is a good reason to run the database as a separate service instead of sharing one file.
Download a copy of the database before a big update#
Persistent storage protects you from rebuilds, but not from a bug in your own code: a broken migration or a stray delete ruins the data just as easily in /data as on your own server. Before a schema change or a large update, open the "Data" tab, download the database file and keep it somewhere safe. If something goes wrong, you can upload the same file back.
Decide whether it is time to move to a real database#
SQLite handles a single process that writes now and then very well: a personal site, a bot, a dashboard, an internal tool for a handful of people. It is time to move on when several processes start writing at once, writes are constant, or the data grows large. That is when locks and waiting start to show up. In that case run a database as a separate service next to the app with docker-compose, or connect an external one and pass the connection string through the same environment variable.
The short version: files next to your code are part of the code, and every deploy returns them to the state you uploaded. Only what lives in persistent storage stays. Move the SQLite file to /data, set the path through an environment variable, and you can ship updates without losing anything. Try Netrun.
Common questions
Where is the /data folder and how do I use it from code?
It is an ordinary folder inside the project at the path /data, and you work with it like any other one: the database file would be, for example, /data/app.db. Its contents are listed on the "Data" tab in your dashboard, where files can be downloaded, uploaded or deleted. You do not need to create the folder yourself, it is there from the first run.
How do I move a database that is already filled with data on my computer?
Deploy the project once so the path matches, then open the "Data" tab and upload the file under the name your app expects. Stop the project while you upload, so the app does not write to the database while the file is being replaced. On the next start your app picks up the database with all the data in it.
Should I include the database file in the archive with my code?
No. A file uploaded together with the code lands next to the code rather than in persistent storage, and the next deploy restores it to exactly the state you uploaded. Keep the database in /data, and if you need seed data, create it from code on first run.
What does the "database is locked" error mean?
SQLite lets only one process write to the database at a time, so the error shows up when several try at once: multiple web server workers, or a background job running alongside a request. Reduce the number of writing processes or spread the writes out in time. If that gets in your way, it is a clear sign to move to a separate database.
What about Django, where the database sits in the project folder by default?
Django sets the database file path explicitly in settings, so read that path from an environment variable and point it inside the persistent folder, for example /data/db.sqlite3. Migrations run exactly as before, they just apply to a file that does not disappear. Other frameworks that default to a database file next to the code are handled the same way.
SQLite or Postgres for a small project?
For a personal site, a bot, a dashboard or a tool used by a few people, SQLite is usually enough: it needs no separate service and fits in a single file. A full database makes sense once several processes write at the same time, the load is constant, or the data grows large. You can switch later by running a database as a separate service next to the app or connecting an external one.
Is my data kept when I update the code?
Yes, as long as your data lives in persistent storage. For a regular project that is the /data folder: anything your app saves there stays in place when you update the code or restart, and you can browse and download the files on the "Data" tab. If you described the services yourself in docker-compose, persistent storage means the named volumes from your file, and such a project has no /data folder. Files written outside persistent storage are created from scratch on the next deploy. Your project link stays the same either way.
How do I update the code of a project that is already published?
Open the project and upload a new version or update it from GitHub. The link stays the same, and your data is kept as long as it lives in persistent storage — the /data folder or a volume from your compose file.
Can I run several services at once?
Yes. With docker-compose you can bring up to five connected services in one project — for example, an app together with a database.