NetrunHome

What to choose

SQLite or PostgreSQL for a bot or a small website

· 6 min read

In short

For a Telegram bot or a small website where a single app talks to the database, SQLite is usually enough: it is one file and needs no separate database server. Choose PostgreSQL when several processes or services write to the database at the same time, when other programs need access to it, or when data and users keep growing. The key hosting rule for SQLite is that the database file must live in persistent storage, otherwise it is reset on the next deploy. PostgreSQL runs as a separate service next to your app or as an external managed database.

  • SQLite keeps the whole database in a single file and runs inside your app, with no separate database server.
  • SQLite allows one writer at a time; WAL mode lets reads run in parallel with a write.
  • PostgreSQL is a separate database server that several apps and services can connect to at once.
  • A SQLite backup is a copy of the database file, while PostgreSQL backups are usually made with pg_dump.
  • Data can be moved from SQLite to PostgreSQL with pgloader, and an ORM such as SQLAlchemy or the Django ORM makes the switch itself easier.

Your bot remembers users, your site stores sign-ups, and at some point you have to decide where the data lives. Bot tutorials almost always use SQLite, articles about real-world development use PostgreSQL, and it starts to feel like SQLite is only for learning. It is not: SQLite works perfectly well in production projects as long as you know its limits.

The difference is not about being serious, it is about design. SQLite is a library that keeps the whole database in one file and runs right inside your app. PostgreSQL is a separate server program that apps connect to over the network. Below is how to choose and how not to lose your data after deploying.

SQLite vs PostgreSQL for a bot or a small website
CriterionSQLitePostgreSQL
Setupnothing to install, the sqlite3 module ships with Pythonneeds a separate database server
Where data livesone file next to the appon the database server, in its own files
Concurrent writesone writer at a time, others waitmany concurrent writes from different processes
Access from several servicesawkward: every service must see the fileyes, over the network with a connection string
Data sizehandles the gigabytes of a small project comfortablybuilt for large volumes and complex queries
Backupcopy the database filepg_dump or your provider's tools
When to switchwhile one app writes and everything is fastseveral services, frequent database is locked errors, growing load
  1. Start with SQLite if a single app uses the database#

    For a single-process bot, a small website, a dashboard or a scraper, SQLite is the simplest choice: the sqlite3 module ships with Python, no server is needed, and the database is one file. It answers a small project's queries quickly and handles thousands of users, as long as writes do not come from many places at once. Turn on WAL mode with one command, PRAGMA journal_mode=WAL, so reads do not wait for writes.

  2. Choose PostgreSQL if several processes or services write#

    You need PostgreSQL when more than one app works with the database: a bot plus an admin site, several copies of a website, or background jobs next to the main process. Another sign is database is locked errors in SQLite, which mean writes come from several places and are getting in each other's way. PostgreSQL is also the better fit if external programs need access, or if you need complex queries or strict access rights.

  3. Keep the SQLite file in a persistent folder#

    On a host the project is rebuilt from your uploaded files on every deploy, so a database written next to the code is reset to its original state. The SQLite file must live in persistent storage, and its path is best set with an environment variable rather than hardcoded. That way the database sits in the project folder on your computer and somewhere that survives updates on the server. Do not upload your local test database along with the code unless you want it to overwrite the real one.

  4. Run PostgreSQL next to the app or connect an external database#

    There are two routes. The first is to describe the database as a separate service in docker-compose next to the app and attach a named volume so the data survives updates. The second is to use a managed PostgreSQL database from a cloud provider, such as Supabase or Neon, and pass the connection string to the app as a secret. The first keeps everything in one project, the second takes backups and database upgrades off your hands.

  5. Set up backups from day one#

    For SQLite a backup is the database file. You can download it, but if WAL mode is on there are files ending in -wal and -shm next to it, and you need to take them together or make the copy with the .backup command. For PostgreSQL, pg_dump exports the database into a single file. Make a copy before every major schema change and keep it somewhere other than the same server.

  6. Switch to PostgreSQL when the signs appear#

    Do not move in advance: if SQLite copes, an extra server is just extra complexity. The signs it is time are database is locked errors, a second app that needs the same data, and queries that are noticeably slowing down. The move is easier if your code talks to the database through an ORM: then you change the connection string and move the data with pgloader or an export and import.

For most bots and small websites SQLite is a sensible choice, not a stopgap: moving to PostgreSQL makes sense once several processes start writing to the database. On Netrun SQLite goes into the persistent /data folder, whose contents survive code updates and restarts, and on the Data tab you can browse, download and upload the database file. PostgreSQL runs as a service in docker-compose with a named volume (such projects use volumes for storage and have no /data folder, and the plan’s memory is shared between services), or you connect an external database. Netrun does not offer a managed database as a separate service. Try Netrun.

Common questions

Is SQLite fine for a Telegram bot with thousands of users?

Yes, if the bot runs as a single process. Bot queries are short, and SQLite handles them with plenty of room to spare. The limit is not the number of users but how many different processes write to the database at the same time.

What does the database is locked error mean?

It means one process is writing to the database while another tries to write too and runs out of patience waiting. WAL mode, short transactions and writing from one place help. If the error keeps coming back, it is a sign the project should move to PostgreSQL.

Why did my SQLite database disappear after a code update?

Because the database file sat next to the code, and the project is rebuilt from your uploaded files on every deploy. Move the file into persistent storage and set its path with an environment variable. After that the database survives updates.

Can I run PostgreSQL on the same host as my bot?

Yes, if the host supports docker-compose: the database is a separate service next to the bot, and its data lives in a named volume. Keep in mind that the database uses memory too, shared with your app. If you would rather not look after a database yourself, connect a managed one from a cloud provider.

Is it hard to move from SQLite to PostgreSQL later?

If your code uses an ORM such as SQLAlchemy, the Django ORM or Prisma, the move comes down to changing the connection string and transferring the data. With raw SQL queries you will need to check the syntax, since some constructs differ between the two. Data is moved with pgloader or an export and import.

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.

Can I run several services at once?

Yes. With docker-compose one project can bring up a whole set of services — an app together with a database, a cache and a background worker, say. We do not cap how many: the real ceiling is the memory and CPU of your plan, which are shared between the services of the project.

Where do I set tokens and other secret values?

Every project has a Secrets tab where you set the values from your code — for example the token from BotFather. We store them encrypted: you can see the variable names, but the values are shown to no one, including you.

Get your own project online

Upload your code, answer a couple of questions and get a working link. There is a free plan

Try Netrun
All blog articles