[GH-ISSUE #1114] Postgres database option #786

Closed
opened 2026-05-07 00:27:29 +02:00 by BreizhHardware · 26 comments

Originally created by @brettinternet on GitHub (May 23, 2024).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/1114

💡 Postgres!
I use ntfy in a kubernetes environment and would like the option of high availability. I also prefer to use a central DB connection over a volume with a sqlite DB.

💻 ntfy server

Originally created by @brettinternet on GitHub (May 23, 2024). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/1114 :bulb: **Postgres!** I use ntfy in a kubernetes environment and would like the option of high availability. I also prefer to use a central DB connection over a volume with a sqlite DB. :computer: **ntfy server**
Author
Owner

@fredrikscode commented on GitHub (Oct 15, 2024):

First result I found while googling "ntfy postgres". I'd love the option of going with postgres or any other type of database server as sqlite bricks over nfs and using volumes is just a very crappy way to deal with storage when running clusters.

<!-- gh-comment-id:2415073933 --> @fredrikscode commented on GitHub (Oct 15, 2024): First result I found while googling "ntfy postgres". I'd love the option of going with postgres or any other type of database server as sqlite bricks over nfs and using volumes is just a very crappy way to deal with storage when running clusters.
Author
Owner

@Ittihadyya commented on GitHub (Jan 12, 2025):

Seconding this, I would prefer being able to slot it into already existing infrastructure than having it run its own SQLite database.

<!-- gh-comment-id:2585628383 --> @Ittihadyya commented on GitHub (Jan 12, 2025): Seconding this, I would prefer being able to slot it into already existing infrastructure than having it run its own SQLite database.
Author
Owner

@giangduong commented on GitHub (Feb 7, 2025):

+1

<!-- gh-comment-id:2642527306 --> @giangduong commented on GitHub (Feb 7, 2025): +1
Author
Owner

@sadorowo commented on GitHub (Jul 4, 2025):

I already use Postgres for various services. It would be nice to connect ntfy to it, instead of having separate databases for no reason.

<!-- gh-comment-id:3037188066 --> @sadorowo commented on GitHub (Jul 4, 2025): I already use Postgres for various services. It would be nice to connect ntfy to it, instead of having separate databases for no reason.
Author
Owner

@gavinmcfall commented on GitHub (Dec 16, 2025):

Also throwing my weight into this one. would love to make this more highly available

<!-- gh-comment-id:3662652028 --> @gavinmcfall commented on GitHub (Dec 16, 2025): Also throwing my weight into this one. would love to make this more highly available
Author
Owner

@PixNyb commented on GitHub (Dec 25, 2025):

Not being able to use an external database doesn't work in my environment and as such keeps me from enjoying the functionalities that ntfy.sh does very well. Can't wait to see this added

<!-- gh-comment-id:3691629850 --> @PixNyb commented on GitHub (Dec 25, 2025): Not being able to use an external database doesn't work in my environment and as such keeps me from enjoying the functionalities that ntfy.sh does very well. Can't wait to see this added
Author
Owner

@binwiederhier commented on GitHub (Dec 26, 2025):

Due to popular demand, I may look into this. FYI I did a relatively straight forward PoC a while back: https://github.com/binwiederhier/ntfy/pull/1095

<!-- gh-comment-id:3693199553 --> @binwiederhier commented on GitHub (Dec 26, 2025): Due to popular demand, I may look into this. FYI I did a relatively straight forward PoC a while back: https://github.com/binwiederhier/ntfy/pull/1095
Author
Owner

@hugosxm commented on GitHub (Jan 2, 2026):

I use gotify now, with the iOS app that is not working :( I really prefer NTFY and I need pgsql support for that because I run k8s too like many people i guess... So big thank you @binwiederhier ! In the meantime I think I will switch back to ntfy with a local volume !

<!-- gh-comment-id:3705621294 --> @hugosxm commented on GitHub (Jan 2, 2026): I use gotify now, with the iOS app that is not working :( I really prefer NTFY and I need pgsql support for that because I run k8s too like many people i guess... So big thank you @binwiederhier ! In the meantime I think I will switch back to ntfy with a local volume !
Author
Owner

@binwiederhier commented on GitHub (Feb 17, 2026):

I have started to implement this here: https://github.com/binwiederhier/ntfy/pull/1611/changes

The design is described in the docs:

By default, ntfy uses SQLite for all database-backed stores. As an alternative, you can configure ntfy to use PostgreSQL
by setting the `database-url` option to a PostgreSQL connection string:

database-url: "postgres://user:pass@host:5432/ntfy"

When `database-url` is set, ntfy will use PostgreSQL for the web push subscription store, the user manager and the
message cache instead of SQLite. The `web-push-file` option is not required in this case.

You can also set this via the environment variable `NTFY_DATABASE_URL` or the command line flag `--database-url`.

Does this sound reasonable?

<!-- gh-comment-id:3911300710 --> @binwiederhier commented on GitHub (Feb 17, 2026): I have started to implement this here: https://github.com/binwiederhier/ntfy/pull/1611/changes The design is described in the docs: ``` By default, ntfy uses SQLite for all database-backed stores. As an alternative, you can configure ntfy to use PostgreSQL by setting the `database-url` option to a PostgreSQL connection string: database-url: "postgres://user:pass@host:5432/ntfy" When `database-url` is set, ntfy will use PostgreSQL for the web push subscription store, the user manager and the message cache instead of SQLite. The `web-push-file` option is not required in this case. You can also set this via the environment variable `NTFY_DATABASE_URL` or the command line flag `--database-url`. ``` Does this sound reasonable?
Author
Owner

@k8ieone commented on GitHub (Feb 17, 2026):

Yess, looking forward to deploying this! ❤️

<!-- gh-comment-id:3915161197 --> @k8ieone commented on GitHub (Feb 17, 2026): Yess, looking forward to deploying this! ❤️
Author
Owner

@RivenSkaye commented on GitHub (Mar 3, 2026):

Due to how the current *-file keys are set up, what would happen if both those keys and a postgres URI are specified?
This could be very useful as a migration path for existing users who would prefer PostgreSQL.

For example:

  • Read in data from sqlite files, INSERT ... ON CONFLICT DO UPDATE on the PostgreSQL DB and warn the user that they should probably be removing the keys from their config.
  • To prevent service restart edge cases, delete the sqlite files.
  • If the config isn't updated, skip the migration code and warn the user about pre-migration remnants instead.
<!-- gh-comment-id:3990255068 --> @RivenSkaye commented on GitHub (Mar 3, 2026): Due to how the current `*-file` keys are set up, what would happen if both those keys _and_ a postgres URI are specified? This _could be_ very useful as a migration path for existing users who would prefer PostgreSQL. For example: - Read in data from sqlite files, [`INSERT ... ON CONFLICT DO UPDATE`](https://www.postgresql.org/docs/18/sql-insert.html) on the PostgreSQL DB and warn the user that they should _probably_ be removing the keys from their config. - To prevent service restart edge cases, delete the sqlite files. - If the config isn't updated, skip the migration code and warn the user about pre-migration remnants instead.
Author
Owner

@binwiederhier commented on GitHub (Mar 3, 2026):

The code is code complete and working well. I have to do a thorough round of regression testing of the entire product before releasing it, but if anyone wants to test it, go wild: https://github.com/binwiederhier/ntfy/pull/1619

It was all done by AI, I have manually reviewed this branch over and over and over again, and I have compared before/after. I also had Cursor created this nice doc for me with a comparison, which I re-did 5-10 times: comparison-2026-03-01.html

--

Due to how the current *-file keys are set up, what would happen if both those keys and a postgres URI are specified?
This could be very useful as a migration path for existing users who would prefer PostgreSQL.

The ntfy server will not allow both to be set. It's either database-url or any of the *-file options.

Migration:
I cannot offer a permanent migration path, that would be insane to have to maintain. I had Cursor write a one-off migration tool (pgimport) in the tools folder of that PR. I tested this with the prod ntfy databases and it seems to work. I have not tested that thoroughly though.

Test plan:

  • Deploy code (unchanged settings, using sqlite) to ntfy staging, using the prod database
  • Test all the things on ntfy staging
  • Stop ntfy server on ntfy staging
  • Perform the pgimport, update configs to database-url
  • Start ntfy server on ntfy staging
  • Test all the things on ntfy staging
  • Perform a load test on ntfy staging, with load similar to the prod ntfy server

Release plan:

  • Assuming all this passes, tag new release, announce it
  • Wait 3-5 days, do not upgrade prod ntfy (let community test sqlite changes + postgres changes)
  • Upgrade prod ntfy server (using old sqlite config)
  • Wait ~7 days (let community test postgres changes)
  • Stop ntfy server on ntfy prod
  • Perform the pgimport, update configs to database-url
  • Start ntfy server on ntfy prod
  • Monitor
<!-- gh-comment-id:3991245185 --> @binwiederhier commented on GitHub (Mar 3, 2026): The code is code complete and working well. I have to do a thorough round of regression testing of the entire product before releasing it, but if anyone wants to test it, go wild: https://github.com/binwiederhier/ntfy/pull/1619 It was all done by AI, I have manually reviewed this branch over and over and over again, and I have compared before/after. I also had Cursor created this nice doc for me with a comparison, which I re-did 5-10 times: [comparison-2026-03-01.html](https://github.com/user-attachments/files/25717103/comparison-2026-03-01.html) -- > Due to how the current *-file keys are set up, what would happen if both those keys and a postgres URI are specified? This could be very useful as a migration path for existing users who would prefer PostgreSQL. The ntfy server will not allow both to be set. It's either `database-url` or any of the `*-file` options. **Migration:** I cannot offer a permanent migration path, that would be insane to have to maintain. I had Cursor write a one-off migration tool (pgimport) in the tools folder of that PR. I tested this with the prod ntfy databases and it seems to work. I have not tested that thoroughly though. **Test plan:** - Deploy code (unchanged settings, using sqlite) to ntfy staging, using the prod database - Test _all the things_ on ntfy staging - Stop ntfy server on ntfy staging - Perform the pgimport, update configs to `database-url` - Start ntfy server on ntfy staging - Test _all the things_ on ntfy staging - Perform a load test on ntfy staging, with load similar to the prod ntfy server **Release plan:** - Assuming all this passes, tag new release, announce it - Wait 3-5 days, do not upgrade prod ntfy (let community test sqlite changes + postgres changes) - Upgrade prod ntfy server (using old sqlite config) - Wait ~7 days (let community test postgres changes) - Stop ntfy server on ntfy prod - Perform the pgimport, update configs to `database-url` - Start ntfy server on ntfy prod - Monitor
Author
Owner

@binwiederhier commented on GitHub (Mar 7, 2026):

Everyone, please test ntfy 2.18.0 and the Postgres support: https://github.com/binwiederhier/ntfy/releases/tag/v2.18.0

You can learn how to configure it here: https://docs.ntfy.sh/config/#postgresql-experimental

TLDR: database-url: "postgres://user:pass@host:5432/ntfy"

<!-- gh-comment-id:4017428043 --> @binwiederhier commented on GitHub (Mar 7, 2026): Everyone, please test ntfy 2.18.0 and the Postgres support: https://github.com/binwiederhier/ntfy/releases/tag/v2.18.0 You can learn how to configure it here: https://docs.ntfy.sh/config/#postgresql-experimental TLDR: `database-url: "postgres://user:pass@host:5432/ntfy"`
Author
Owner

@k8ieone commented on GitHub (Mar 8, 2026):

Switched my instance today without any issues.

I didn't do any imports, fresh start. I didn't have anything persistent on my instance that I wouldn't mind losing.

We'll see how it holds up, my instance is mainly used as a UnifiedPush distributor.

Thank you for your work on this @binwiederhier ❤️

<!-- gh-comment-id:4018978593 --> @k8ieone commented on GitHub (Mar 8, 2026): Switched my instance today without any issues. I didn't do any imports, fresh start. I didn't have anything persistent on my instance that I wouldn't mind losing. We'll see how it holds up, my instance is mainly used as a UnifiedPush distributor. Thank you for your work on this @binwiederhier ❤️
Author
Owner

@binwiederhier commented on GitHub (Mar 8, 2026):

Thanks for the feedback @k8ieone

<!-- gh-comment-id:4019075776 --> @binwiederhier commented on GitHub (Mar 8, 2026): Thanks for the feedback @k8ieone
Author
Owner

@cmuench commented on GitHub (Mar 8, 2026):

I was able to import two sqlite dbs into my postgtres server with the pgimport tool. Everything works well.
Thanks @k8ieone

<!-- gh-comment-id:4019682363 --> @cmuench commented on GitHub (Mar 8, 2026): I was able to import two sqlite dbs into my postgtres server with the pgimport tool. Everything works well. Thanks @k8ieone
Author
Owner

@FAUSheppy commented on GitHub (Mar 10, 2026):

Worked like a charm so far, will test the cli/acls & stuff later this week. Thanks for this great feature!

<!-- gh-comment-id:4033465455 --> @FAUSheppy commented on GitHub (Mar 10, 2026): Worked like a charm so far, will test the cli/acls & stuff later this week. Thanks for this great feature!
Author
Owner

@binwiederhier commented on GitHub (Mar 10, 2026):

Thank you for testing folks. Keep the feedback coming! I'll likely switch ntfy.sh next weekend unless I hear anything that will make me stop it.

<!-- gh-comment-id:4033993853 --> @binwiederhier commented on GitHub (Mar 10, 2026): Thank you for testing folks. Keep the feedback coming! I'll likely switch ntfy.sh next weekend unless I hear anything that will make me stop it.
Author
Owner

@FAUSheppy commented on GitHub (Mar 10, 2026):

Only minor complaint about the error handling:

  1. When putting in an invalid database URL, it seemingly silently defaults to a localhost connection and this combined with...
  2. ..the error handling here, is a bit awkward because it doesn't say, that the Database Ping failed.

This left me confused about the actual problem.

Idk what this check does exactly, but with this URL it did break (meaning it didn't fail where it should):

postgresql+psycopg2://notification-management:PW@8.8.8.8/notification-management?sslmode=require

(the URL is wrong, I'm just yapping about the unclear error)

<!-- gh-comment-id:4034135365 --> @FAUSheppy commented on GitHub (Mar 10, 2026): Only minor complaint about the error handling: 1. When putting in an invalid database URL, it seemingly silently defaults to a localhost connection and this combined with... 2. ..the error handling [here](https://github.com/binwiederhier/ntfy/blob/bcd07115c24faf7dc6074a876950070fa40bfeef/db/pg/pg.go#L64), is a bit awkward because it doesn't say, that the **Database** Ping failed. This left me confused about the actual problem. Idk what [this check](https://github.com/binwiederhier/ntfy/blob/bcd07115c24faf7dc6074a876950070fa40bfeef/db/pg/pg.go#L28) does exactly, but with this URL it did break (meaning it didn't fail where it should): postgresql+psycopg2://notification-management:PW@8.8.8.8/notification-management?sslmode=require (the URL is wrong, I'm just yapping about the unclear error)
Author
Owner

@binwiederhier commented on GitHub (Mar 10, 2026):

@FAUSheppy That's great feedback. I hate bad error messages. I'll improve this.

<!-- gh-comment-id:4034434057 --> @binwiederhier commented on GitHub (Mar 10, 2026): @FAUSheppy That's great feedback. I hate bad error messages. I'll improve this.
Author
Owner

@binwiederhier commented on GitHub (Mar 11, 2026):

@FAUSheppy Done: github.com/binwiederhier/ntfy@997e20fa3f

<!-- gh-comment-id:4035520298 --> @binwiederhier commented on GitHub (Mar 11, 2026): @FAUSheppy Done: https://github.com/binwiederhier/ntfy/commit/997e20fa3f70920097b4deb376b7f2f38b6c6dc3
Author
Owner

@kyuuk commented on GitHub (Mar 11, 2026):

just migrated to postgres using the pgimport tool (users.db), everything is good, tested some notification and nothing to report except that it works 😄

<!-- gh-comment-id:4042556539 --> @kyuuk commented on GitHub (Mar 11, 2026): just migrated to postgres using the `pgimport` tool (users.db), everything is good, tested some notification and nothing to report except that it works 😄
Author
Owner

@hugosxm commented on GitHub (Mar 13, 2026):

Sorry for the delay, tested everything today, works like a charm but did not test the migration as I took the opportunity to start from a fresh instance and brand new token / secrets. Thanks a lot for that change !
Is this possible to cache attachements to postgres too ? It would make ntfy fully stateless !

Also can we run multiple replicas of ntfy with postgres ?

<!-- gh-comment-id:4057462503 --> @hugosxm commented on GitHub (Mar 13, 2026): Sorry for the delay, tested everything today, works like a charm but did not test the migration as I took the opportunity to start from a fresh instance and brand new token / secrets. Thanks a lot for that change ! Is this possible to cache attachements to postgres too ? It would make ntfy fully stateless ! Also can we run multiple replicas of ntfy with postgres ?
Author
Owner

@binwiederhier commented on GitHub (Mar 13, 2026):

Is this possible to cache attachements to postgres too ?

My plan was S3 bucket/adapter, but I guess pg could be an idea too.

Also can we run multiple replicas of ntfy with postgres ?

I merged in DB replica support yesterday (not released yet):

database-url: "postgres://user:pass@primary:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"
database-replica-urls:
  - "postgres://user:pass@replica1:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"
  - "postgres://user:pass@replica2:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"

You can NOT yet run multiple instances of ntfy yet. There is in-memory state that prevents that. I will add that once I have attachments and replicas fully rolled out.

The postgres push was just step one into making it clusterable or at least more horizontally scalable.

<!-- gh-comment-id:4057486051 --> @binwiederhier commented on GitHub (Mar 13, 2026): > Is this possible to cache attachements to postgres too ? My plan was S3 bucket/adapter, but I guess pg could be an idea too. > Also can we run multiple replicas of ntfy with postgres ? I merged in DB replica support yesterday (not released yet): ``` database-url: "postgres://user:pass@primary:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" database-replica-urls: - "postgres://user:pass@replica1:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" - "postgres://user:pass@replica2:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" ``` You can NOT yet run multiple instances of ntfy yet. There is in-memory state that prevents that. I will add that once I have attachments and replicas fully rolled out. The postgres push was just step one into making it clusterable or at least more horizontally scalable.
Author
Owner

@k8ieone commented on GitHub (Mar 13, 2026):

omg, yesss! You're building towards dream HA!

<!-- gh-comment-id:4057981953 --> @k8ieone commented on GitHub (Mar 13, 2026): omg, yesss! You're building towards dream HA!
Author
Owner

@hugosxm commented on GitHub (Mar 13, 2026):

Is this possible to cache attachements to postgres too ?

My plan was S3 bucket/adapter, but I guess pg could be an idea too.

Also can we run multiple replicas of ntfy with postgres ?

I merged in DB replica support yesterday (not released yet):

database-url: "postgres://user:pass@primary:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"
database-replica-urls:
  - "postgres://user:pass@replica1:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"
  - "postgres://user:pass@replica2:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30"

You can NOT yet run multiple instances of ntfy yet. There is in-memory state that prevents that. I will add that once I have attachments and replicas fully rolled out.

The postgres push was just step one into making it clusterable or at least more horizontally scalable.

Thanks for the clarification, postgres seems easier as a user if you already have the DB. S3 is nice too but this is an additional component to run if you not already have it.

I would be glad to test HA once it is ready ;)

<!-- gh-comment-id:4057999472 --> @hugosxm commented on GitHub (Mar 13, 2026): > > Is this possible to cache attachements to postgres too ? > > My plan was S3 bucket/adapter, but I guess pg could be an idea too. > > > Also can we run multiple replicas of ntfy with postgres ? > > I merged in DB replica support yesterday (not released yet): > > ``` > database-url: "postgres://user:pass@primary:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" > database-replica-urls: > - "postgres://user:pass@replica1:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" > - "postgres://user:pass@replica2:5432/ntfy?sslmode=require&sslrootcert=/etc/ntfy/db-ca-cert.pem&pool_max_conns=30" > ``` > > You can NOT yet run multiple instances of ntfy yet. There is in-memory state that prevents that. I will add that once I have attachments and replicas fully rolled out. > > The postgres push was just step one into making it clusterable or at least more horizontally scalable. > Thanks for the clarification, postgres seems easier as a user if you already have the DB. S3 is nice too but this is an additional component to run if you not already have it. I would be glad to test HA once it is ready ;)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#786
No description provided.