Where to run Postgres or SQLite for a side project: 10 options and what each costs

By

Supabase, Neon, Turso, Cloudflare D1, Railway, Fly.io, DigitalOcean, Prisma Postgres, PlanetScale and plain SQLite: free tiers, first paid step and catches.

~~~

A side project needs a database that costs close to nothing while nobody uses it, and doesn’t need a DBA when somebody does. Here are ten places to run Postgres or SQLite, with the free tier, the first paid step, the thing that will bite you, and how you connect from Node.

I checked every price on the provider’s own pricing page on September 16, 2026. This is the database half of where to host your web app.

OptionEngineFree tierFirst paid stepBiggest catch
SupabasePostgres2 projects, 500 MB eachPro, $25/monthPaused after 1 week idle
NeonPostgres100 CU-hours and 0.5 GB per projectLaunch, usage-based, no minimumCold starts after 5 minutes idle
TursoSQLite (libSQL)100 databases, 5 GB, 500M rows read/monthDeveloper, $5.99/monthReads are rows scanned
Cloudflare D1SQLite5M rows read/day, 5 GBWorkers Paid, $5/month10 GB cap per database, Workers only
Railway PostgresPostgres30-day trial, then $1 credit/monthHobby, $5/monthContainer runs all month
Fly.io PostgresPostgresTrial only (2 hours or 7 days)Managed Basic, $38/monthHighest entry price here
DigitalOceanPostgresNoneManaged, $15.15/month, or a $4 DropletManaged is 2.5x the Droplet
Prisma PostgresPostgres200k operations, 500 MBStarter, $10/monthEvery query is a metered operation
PlanetScalePostgresNoneSingle node, $5/monthDisk and backups billed on top
SQLite on your serverSQLiteFree with the serverThe server itselfBackup is your job

Here are the first paid steps side by side. Neon isn’t in the chart because its paid plan has no minimum, you pay for what you use:

xychart-beta horizontal
  title "First paid step ($ per month)"
  x-axis ["D1", "Railway", "PlanetScale", "Turso", "Prisma", "DigitalOcean", "Supabase", "Fly.io"]
  y-axis 0 --> 40
  bar [5, 5, 5, 5.99, 10, 15.15, 25, 38]

Most options start at around $5. Supabase and Fly.io are the two outliers, at $25 and $38 a month.

What I run myself: D1 in StackPlan, SQLite files in local tools like Events Logger, and Postgres inside Docker on a $6 DigitalOcean Droplet for my self-hosted Plausible. For the rest I’m reporting what the pricing pages say, not what my bill says.

1. Supabase

Supabase gives you a Postgres database plus auth, file storage, and a REST API generated from your tables.

The Free plan gives you two active projects, each with a 500 MB database on a shared CPU with 500 MB of RAM, 5 GB of egress and 1 GB of file storage. Pro starts at $25 a month for the first project (extra projects from $10 each): 8 GB of disk, 250 GB of egress, daily backups kept for seven days, and $10 of compute credits, enough for one Micro instance (2-core ARM, 1 GB of RAM).

The catch is pausing. Free projects are paused after one week of inactivity, and a hobby app nobody visits for a week is down until you unpause it in the dashboard. Backups are also a Pro feature.

From a serverless function, connect through the transaction pooler on port 6543 and turn off prepared statements, because transaction mode doesn’t support them:

import postgres from 'postgres'

const sql = postgres(process.env.DATABASE_URL, { prepare: false })

const posts = await sql`select id, title from posts order by created_at desc`

The direct connection on port 5432 is IPv6 only unless you buy the IPv4 add-on.

I wrote a Supabase setup guide in 2022 if you want the step-by-step.

2. Neon

Neon is serverless Postgres. Compute scales to zero when idle and wakes up on the next query, and you can branch the database like a Git repository. Neon is now part of Databricks (the plan pages say Lakebase Postgres), but what you connect to is Postgres.

The Free plan allows 100 projects. Each gets 100 compute-hours (CU-hours) a month, 0.5 GB of storage and 10 branches. Compute scales to zero after five minutes idle.

Launch, the first paid plan, has no monthly minimum: $0.106 per CU-hour, $0.35 per GB-month of storage, $0.002 per branch-hour beyond the included ten. Neon’s own estimate for a small database with intermittent load and 1 GB of data is about $15 a month.

Cold starts are the first catch. A parked database takes a moment to come back (Neon quotes 350 ms). The second is CU-hour math: the bill depends on how long compute stays awake, not on rows touched, so a cron job polling every minute keeps it running all month and past the free 100 hours.

Any Postgres driver works. Neon also has one that talks HTTP instead of TCP, for Workers and Vercel functions:

import { neon } from '@neondatabase/serverless'

const sql = neon(process.env.DATABASE_URL)

const [post] = await sql`select * from posts where slug = ${slug}`

The Postgres in the Vercel Marketplace is Neon billed through your Vercel account.

3. Turso

Turso hosts SQLite. It started with libSQL, a fork of SQLite with a network protocol, and now offers two database types, libSQL databases and a newer engine it calls Turso Database, both speaking SQLite’s SQL.

The Free plan is 100 databases, 5 GB of storage, 500 million rows read and 10 million rows written a month, 3 GB of sync traffic, and one day of point-in-time restore. Developer is $5.99 a month billed monthly ($4.99 yearly): unlimited databases, 9 GB, 2.5 billion rows read, 25 million written, ten days of restore, and Scaler follows at $29.

Watch how reads are counted. A query on an unindexed column scans the table and every scanned row counts, so a missing index on a million-row table costs a million reads per query. Idle databases cost storage only, which is why one database per user is a normal pattern here.

import { createClient } from '@libsql/client'

const db = createClient({
  url: process.env.TURSO_DATABASE_URL,
  authToken: process.env.TURSO_AUTH_TOKEN,
})

const result = await db.execute('select * from posts where published = 1')

@libsql/client is also what Drizzle and Prisma use for Turso. I wrote a full libSQL and Turso guide with the CLI setup and embedded replicas.

4. Cloudflare D1

D1 is SQLite inside Cloudflare’s network, queried from a Worker through a binding. There’s no server to connect to: your Worker gets an env.DB object and runs SQL on it. I use it for the relational data in StackPlan, including a first-party analytics events table.

The Workers Free plan includes 5 million rows read and 100,000 rows written a day, 5 GB of storage across up to 10 databases, and seven days of Time Travel (point-in-time restore). Workers Paid is $5 a month for the account: 25 billion rows read and 50 million written a month, 5 GB of storage and then $0.75 per GB-month, 30 days of Time Travel, up to 50,000 databases, no egress charge. Free limits reset at 00:00 UTC, and until then queries fail.

The hard limit is 10 GB per database, and it cannot be raised. Reads are rows scanned, same as Turso. And your code has to run on Workers or Pages Functions to use the binding; there’s a REST API, but D1 is at its best when the app lives next to it.

export default {
  async fetch(request, env) {
    const post = await env.DB.prepare(
      'select * from posts where slug = ?'
    ).bind('database-hosting-options').first()

    return Response.json(post)
  },
}

Migrations go through Wrangler, and you can run D1 locally with the same commands. I wrote a D1 introduction and a walkthrough of Astro SSR with D1 and Drizzle, and the free Cloudflare D1 course puts it all in order.

5. Railway Postgres

Railway runs your app and your database as services in one project. Postgres is a one-click template on the official Docker image with a volume attached.

The Free plan is a 30-day trial with $5 of credit, then $1 of free credit a month, with services capped at 1 vCPU, 0.5 GB of RAM and 0.5 GB of volume. Hobby is $5 a month and includes $5 of usage. Beyond that, RAM is $10 per GB per month, CPU $20 per vCPU per month, volumes $0.15 per GB and egress $0.05 per GB. A Postgres container holding 256 MB of RAM costs about $2.50 a month in memory before CPU, so the database alone sits inside the Hobby credit.

The container runs all month, idle or not, and that’s what you pay for. Databases are private by default, and exposing one through the TCP proxy to reach it from your laptop bills that traffic as egress. After the trial, $1 of credit a month buys about 100 MB of RAM, so the Free plan is a trial.

You point the app at the database with a variable reference, and Railway fills in the private URL, which pg or postgres then reads as usual:

DATABASE_URL=${{Postgres.DATABASE_URL}}

I walked through deploying an Astro and PostgreSQL app on Railway this way.

If you sign up, use my referral link: you get $20 in Railway credit, and I get a 15% commission on what you pay in your first year.

6. Fly.io Postgres

Fly.io has two Postgres products.

Fly Postgres, the older one, is labelled unmanaged. It’s a Fly app with flyctl helpers to bootstrap a cluster, and Fly’s docs say they can’t provide support or guidance for it. The cheapest machine is a shared-cpu-1x with 256 MB of RAM at $1.94 a month ($2.19 from October 1, 2026, when Fly raises its RAM price), plus $0.15 per GB of volume, so a small unmanaged Postgres runs under $4 a month if 256 MB is enough.

Managed Postgres is the new one. Every plan includes high availability, automated backups and connection pooling. Basic, the smallest, is shared-2x with 1 GB of RAM at $38 a month, plus $0.28 per provisioned GB of storage ($2.80 for the default 10 GB volume). Starter with 2 GB is $72. There is no free tier: the trial is 2 hours of machine runtime or 7 days, whichever comes first.

The catch is the price gap: $38 a month is the highest entry price here, and the unmanaged option is cheap because you keep it alive.

fly mpg create
fly mpg attach <cluster-id> -a my-astro-app

The attach step sets a DATABASE_URL secret on the app pointing at the pooled connection (PgBouncer). Fly makes sense if your app already runs on Fly Machines. For a side project that might die, $38 a month is hard to justify before it has users.

7. DigitalOcean: Managed Postgres, or a Droplet you run yourself

DigitalOcean sells both a managed Postgres cluster and plain Linux VMs (Droplets) where you install whatever you want.

The smallest managed Postgres cluster is 1 GiB of RAM, 1 vCPU and 10 GiB of disk at $15.15 a month. It’s a single node, so no high availability, but you get daily backups with point-in-time recovery for the previous seven days, connection pooling, and updates handled for you. Extra disk is $0.215 per GiB a month.

The Droplet route: a Basic Droplet with 512 MiB of RAM, 10 GB of SSD and 500 GiB of transfer is $4 a month, the 1 GiB / 25 GB one is $6. Install Postgres on it (sudo apt install postgresql on Ubuntu), or use a SQLite file, which is option 10. Automated Droplet backups add 20% of the price for weekly snapshots or 30% for daily ones.

My self-hosted Plausible runs that way, on a $6 Droplet with Docker Compose, Postgres and ClickHouse in containers on the same box (I wrote up how to self-host Plausible).

The trade is who does the work. The managed cluster costs two and a half times the Droplet, and in exchange you never upgrade Postgres by hand or test a restore at two in the morning. If you’ve never run a server, start with how to create your first VPS on DigitalOcean; the free PostgreSQL course covers installing it, roles, pools and restoring backups.

The managed cluster is a standard connection string with SSL required:

import postgres from 'postgres'

const sql = postgres(process.env.DATABASE_URL, { ssl: 'require' })

If you sign up, use my DigitalOcean referral link and you get $200 in credit for 60 days. This is an affiliate link: if you sign up through it and then spend $25, I get $25 in DigitalOcean credit.

Hetzner is the cheaper VPS. I keep provider prices for hostingpicker.dev, and when I last checked on August 27, 2026, a CX23 with 2 shared vCPUs, 4 GB of RAM and 40 GB of disk was €5.99 a month with an IPv4 address, in Germany or Finland.

8. Prisma Postgres

Prisma Postgres is the hosted Postgres from the team behind the Prisma ORM. You don’t have to use the ORM: every database gets two standard connection strings, a pooled one and a direct one, and any driver works.

The Free plan needs no credit card: 200,000 database operations a month, 500 MB of storage, up to 50 databases, 10 connections. Starter is $10 a month: 1 million operations and then $8 per million, 10 GB of storage and then $2 per GB, 100 pooled connections, seven days of daily backups, and a hard spend limit.

The catch is the meter. An operation is one query, whether it’s a one-row read or a five-table join, so a page that runs eight queries costs eight operations. 200,000 a month is about 6,600 a day, fine for a hobby app, tight for a dashboard that refreshes, so count your queries per page before you rely on the free tier. Backups start with Starter.

The pooled host is pooled.db.prisma.io and the direct one is db.prisma.io, both on port 5432 with sslmode=require:

import postgres from 'postgres'

const sql = postgres(process.env.DATABASE_URL)

const [{ count }] = await sql`select count(*) from posts`

9. PlanetScale Postgres

PlanetScale made its name with Vitess and MySQL, and now sells Postgres too: a plain cluster, or Neki, its sharded Postgres for very large databases. For a side project you want the plain one.

Pricing is resource-based with no contract. The smallest single-node Postgres, PS-5, has 1/16 of a vCPU and 512 MiB of RAM at $5 a month. The same size as a high-availability cluster, one primary and two replicas across three availability zones, is $15. Disk, backup storage and egress are billed on top, and there’s no free plan on the pricing page.

Entry-level compute is tiny and there’s no free tier. PlanetScale’s own description of the single-node tier is “development and low-traffic production workloads”. What you’re paying for at $5 is the platform around the database: branching, query insights, automated backups (you pay for the backup storage).

Connections go through PgBouncer on port 6432, or straight to Postgres on 5432, with sslmode=verify-full:

postgresql://<user>:<password>@aws-us-east-1-3.pg.psdb.cloud:6432/postgres?sslmode=verify-full&sslrootcert=system

At the hobby stage, $5 a month with disk and backups billed separately is a harder sell than the free tiers above.

10. SQLite on the same server as the app

Option ten is no database server at all. SQLite is a library, the database is one file on disk, and your app opens it directly. If your app already runs on a VPS, it costs nothing on top of the server.

Node has this built in. The node:sqlite module needs no flag since Node 22.13, and the Node docs mark it as a release candidate as of September 2026. The API is synchronous:

import { DatabaseSync } from 'node:sqlite'

const db = new DatabaseSync('/var/lib/myapp/app.db')

db.exec('create table if not exists posts (id integer primary key, title text)')
db.prepare('insert into posts (title) values (?)').run('Hello')

console.log(db.prepare('select * from posts').all())

better-sqlite3 is the long-standing alternative with the same synchronous model (version 13 as of September 2026). I wrote about node:sqlite in detail, and the free SQLite course covers transactions, indexes and operations. My Events Logger keeps every event in a local SQLite file through Drizzle.

Backup is now your job, and the file lives on one machine.

Litestream streams every change to object storage. Version 0.5 replicates to S3-compatible services, including Cloudflare R2, where the first 10 GB a month are free and egress is free. On your Mac, brew install benbjohnson/litestream/litestream. On the server, the .deb from the GitHub releases page installs a systemd service that reads /etc/litestream.yml:

dbs:
  - path: /var/lib/myapp/app.db
    replica:
      type: s3
      bucket: myapp-backups
      path: app
      endpoint: ${CF_ACCOUNT_ID}.r2.cloudflarestorage.com
      region: auto
      access-key-id: ${R2_ACCESS_KEY}
      secret-access-key: ${R2_SECRET_KEY}

litestream replicate runs next to your app, and litestream restore rebuilds the file from R2 on a new server.

The lower-tech way is a nightly copy. SQLite can make a consistent copy of a live database:

sqlite3 /var/lib/myapp/app.db ".backup '/var/backups/app-$(date +%F).db'"

Put that in cron and copy the result to R2. You lose at most a day.

This works for a single-server app with one process writing. It does not work across several machines, or on a serverless platform where the filesystem is gone after each request. When you outgrow it, pgloader moves the file into Postgres in one command.

What I would pick

A hobby app that may die. Put the data where idle costs nothing and nobody has to unpause anything. On Workers, D1 on the free plan. If it needs Postgres, Neon’s free plan, because compute parks itself and comes back without you. Supabase’s free plan works if you visit the app at least weekly, otherwise it’s paused when a friend finally tries it. If you already pay for a VPS, a SQLite file next to the app costs zero.

A side project that might make money. Pay for the thing you don’t want to do yourself, which is backups. Supabase Pro at $25 gets you daily backups, 8 GB and the auth you’d otherwise build. Neon Launch has no minimum and lands around $15 for a small database. Workers Paid at $5 covers D1 with 30 days of Time Travel. Railway Hobby at $5 if you want app and database on one bill. I would leave Fly Managed Postgres for later, because $38 a month is a price for a project that already has users.

Something you must be able to move later. Stay on standard connection strings and standard drivers. A Postgres reached through a postgres:// URL with pg or postgres moves between Supabase, Neon, Railway, DigitalOcean, Prisma Postgres and PlanetScale with pg_dump and a new URL. A SQLite file moves by copying it. What doesn’t move is the platform-shaped code: the D1 binding, Turso’s URL and auth token, Neon’s HTTP driver. Keep those in one module so the swap is one file, and consider Drizzle or Kysely, which speak both Postgres and SQLite.

That’s also where I ended up, without planning it: Postgres on a Droplet I control, SQLite files for tools, and D1 only where the app is already a Worker.

Tagged: Database · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about database: