ntfy vs Gotify: Self-Hosted Push Notifications

Quick Verdict

ntfy wins for most self-hosting setups. It supports UnifiedPush (the open standard for push notifications on Android), works without an account via topic-based pub/sub, and has a public cloud fallback at ntfy.sh if your server goes down. Gotify is the better pick if you want a persistent web dashboard with a plugin system and don’t care about UnifiedPush.

What These Apps Do

Both ntfy and Gotify let you send push notifications to your phone and browser from scripts, automation tools, and monitoring systems. The classic use case: your backup script finishes at 3 AM and you get a ping on your phone. Or Uptime Kuma detects your server is down and fires an alert.

They solve the same problem but take fundamentally different approaches. ntfy is topic-based and stateless — you publish a message to a topic and anyone subscribed gets it. Gotify is application-based and persistent — you create apps in a web UI, each gets a token, and messages are stored in a database.

Architecture: The Core Difference

This is the single biggest distinction and it affects everything else.

ntfy uses a pub/sub model. You pick a topic name (any string), POST a message to it, and every subscriber on that topic receives it. No accounts required for basic use. No application tokens to manage. The simplicity is the point — curl -d "Backup done" ntfy.example.com/backups and you’re finished.

Gotify uses an application model. You log into a web UI, create an “application” (like “Server Alerts” or “Home Assistant”), and get an API token. Messages sent with that token appear under that application in the dashboard. It’s more structured but requires more setup per notification source.

Neither approach is wrong — they optimize for different workflows. ntfy optimizes for fire-and-forget notifications from scripts. Gotify optimizes for organized, categorized alert management through a dashboard.

Feature Comparison

FeaturentfyGotify
ArchitectureTopic-based pub/subApplication-based with tokens
LanguageGoGo
UnifiedPushYes (reference implementation)No
Public cloud fallbackYes (ntfy.sh)No
Web UIMessage viewer, topic managementFull dashboard with app management
Plugin systemNoYes (Go-based plugins)
AuthenticationOptional (default: open)Required (user/password)
End-to-end encryptionYes (client-side)No
Scheduled deliveryYes (send messages at a future time)No
Message priority5 levels (min, low, default, high, urgent)1-10 scale
File attachmentsYes (up to 15 MB default)Yes (via message extras)
Click actionsYes (open URL, view, broadcast)Yes (via client)
iOS appYes (via upstream relay)No official app
Android appYes (F-Droid + Play Store)Yes (F-Droid + Play Store)
Progressive Web AppYesYes
WebSocket supportYesYes (primary delivery method)
Message persistenceSQLite cache (configurable TTL)SQLite/MySQL/PostgreSQL
Multi-userYes (with auth enabled)Yes
API styleREST + WebSocket + SSEREST + WebSocket
Docker image size~15 MB~20 MB
Rate limitingBuilt-in, configurableNo built-in rate limiting

Docker Compose: ntfy

Create a directory for ntfy and add these files:

docker-compose.yml:

services:
  ntfy:
    image: binwiederhier/ntfy:v2.17.0
    container_name: ntfy
    command:
      - serve
    environment:
      TZ: UTC
    volumes:
      - ntfy-cache:/var/cache/ntfy
      - ./server.yml:/etc/ntfy/server.yml:ro
    ports:
      - "8093:80"
    healthcheck:
      test: ["CMD-SHELL", "wget -q --tries=1 http://localhost:80/v1/health -O - | grep -Eo '\"healthy\"\\s*:\\s*true' || exit 1"]
      interval: 60s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

volumes:
  ntfy-cache:

server.yml (ntfy configuration):

# ntfy server configuration
# Full reference: https://docs.ntfy.sh/config/

# Public-facing URL of your ntfy instance
# Required for attachments and email integration
base-url: "https://ntfy.example.com"

# Message cache — stores messages so clients can retrieve missed notifications
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "24h"

# Attachment settings
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "1G"
attachment-file-size-limit: "15M"
attachment-expiry-duration: "6h"

# Upstream server for iOS push notifications
# Required if you use the ntfy iOS app
upstream-base-url: "https://ntfy.sh"

# Access control (uncomment to require authentication)
# auth-file: "/var/cache/ntfy/auth.db"
# auth-default-access: "deny-all"

Send a test notification:

curl -d "Hello from ntfy" http://localhost:8093/test-topic

Subscribe to the topic test-topic in the ntfy Android/iOS app or open http://localhost:8093/test-topic in your browser.

Docker Compose: Gotify

docker-compose.yml:

services:
  gotify:
    image: gotify/server:2.9.0
    container_name: gotify
    environment:
      TZ: UTC
      GOTIFY_DEFAULTUSER_PASS: "changeme"  # Change this — default admin password
    volumes:
      - gotify-data:/app/data
    ports:
      - "8094:80"
    restart: unless-stopped

volumes:
  gotify-data:

Start the stack:

docker compose up -d

Open http://localhost:8094 and log in with admin / changeme. Create an application in the web UI — Gotify generates an API token for it. Then push a test message:

curl "http://localhost:8094/message?token=YOUR_APP_TOKEN" \
  -F "title=Test" \
  -F "message=Hello from Gotify" \
  -F "priority=5"

Sending Notifications: Developer Experience

This is where the architectural difference matters most in practice.

ntfy is the fastest path from “I want a notification” to “my phone buzzed.” Zero setup for basic use:

# One-liner from any script
curl -d "Disk usage above 90%" ntfy.example.com/server-alerts

# With priority, title, and tags
curl \
  -H "Title: Backup Failed" \
  -H "Priority: high" \
  -H "Tags: warning,backup" \
  -d "Restic backup to B2 failed with exit code 1" \
  ntfy.example.com/backups

# Schedule a message for later
curl -H "At: tomorrow, 9am" -d "Run apt upgrade" ntfy.example.com/reminders

Gotify requires creating an application first, but gives you organized categorization:

# Requires an app token from the web UI
curl "http://gotify.example.com/message?token=AhD3p..." \
  -F "title=Backup Failed" \
  -F "message=Restic backup to B2 failed with exit code 1" \
  -F "priority=8"

Both integrate with most self-hosted tools. Home Assistant, Uptime Kuma, Grafana, n8n, and Prometheus Alertmanager all support ntfy and Gotify as notification targets.

ntfy has an edge in automation tools because the topic-based approach means you don’t need to provision tokens. In n8n, you just fire an HTTP request at a topic. With Gotify, you need to create the application and store the token as a credential.

UnifiedPush: ntfy’s Killer Feature

UnifiedPush is an open standard for delivering push notifications on Android without relying on Google’s Firebase Cloud Messaging (FCM). ntfy is the reference implementation of a UnifiedPush distributor.

This matters because:

  • Apps supporting UnifiedPush (Element, FluffyChat, Tusky, Fedilab, and dozens more) can route their push notifications through your ntfy server instead of Google
  • You get real-time push notifications without any Google services on your phone
  • It works on degoogled Android ROMs like GrapheneOS and LineageOS

Gotify has no UnifiedPush support. If you run a degoogled phone or care about eliminating Google dependencies from your notification pipeline, ntfy is the only option.

Gotify’s Plugin System

Gotify’s plugin system lets you extend the server with Go plugins. Plugins can:

  • Register custom HTTP handlers (build webhook receivers)
  • Send messages as applications (poll an RSS feed and push updates)
  • Access persistent storage per user
  • Display dynamic instructions in the web UI

Practical examples: a plugin that receives GitHub webhooks and converts them to Gotify notifications, or one that monitors an RSS feed and alerts on new entries.

The limitation: plugins must be compiled as Go shared objects, and they only work on Linux and macOS. This is a niche feature, but for users who want their notification server to also be a webhook receiver, it adds real value.

ntfy has no plugin system. You handle webhook-to-notification logic externally (which most people do anyway via n8n or a shell script).

Performance and Resources

Both are Go binaries and extremely lightweight.

MetricntfyGotify
Idle RAM~15 MB~20 MB
RAM under moderate load (100 msgs/hour)~30 MB~35 MB
CPU at idleNegligibleNegligible
Docker image (compressed)~15 MB~20 MB
Startup time<1 second<1 second
DatabaseSQLite (cache only)SQLite (default), MySQL, PostgreSQL

Neither app will strain any hardware you’re running. A Raspberry Pi handles either one without breaking a sweat. If you’re already running Home Assistant, Uptime Kuma, or other self-hosted tools, adding ntfy or Gotify has zero meaningful resource impact.

Gotify’s support for MySQL and PostgreSQL gives it an advantage in high-availability setups where you want the notification database on an external database server. ntfy uses SQLite exclusively and treats message storage as a cache with a TTL — it’s not designed for long-term message archival.

Web UI

ntfy has a functional web interface for subscribing to topics, viewing messages, and managing access control (when auth is enabled). It’s clean but minimal — this is not a dashboard, it’s a message viewer.

Gotify has a more full-featured web dashboard. You manage applications, users, clients, and plugins from the UI. Messages are organized by application with clear visual priority indicators. You can send test messages directly from the interface and manage API tokens.

If you want a central place to see all your notification history organized by source, Gotify’s web UI is significantly better. If you just want to confirm messages are flowing and manage subscriptions, ntfy’s UI is sufficient.

Mobile Apps

Both offer Android apps on F-Droid and the Google Play Store.

ntfy’s Android app supports UnifiedPush distribution, instant delivery via WebSocket, and works with both the public ntfy.sh server and your self-hosted instance. Battery usage is minimal because it maintains a single persistent connection.

ntfy’s iOS app works but requires the upstream-base-url setting pointed at https://ntfy.sh because Apple Push Notification Service (APNs) requires a relay. Your messages briefly pass through ntfy.sh’s servers for iOS delivery. If that’s a privacy concern, the PWA is an alternative.

Gotify’s Android app connects via WebSocket to your self-hosted server. Delivery is reliable and instant. There is no official iOS app — Gotify’s maintainers cite the requirement for an Apple Developer account ($99/year) as the blocker. A community-built iOS shortcut exists, but it requires polling rather than push.

Winner: ntfy for cross-platform support. Gotify for Android-only setups where the simpler app model is preferred.

Use Cases

Pick ntfy If…

  • You use UnifiedPush-compatible apps (Element, Tusky, FluffyChat)
  • You run a degoogled phone and need push notifications without FCM
  • You want the fastest possible setup for script notifications
  • You need iOS support
  • You want a public cloud fallback if your server goes down
  • You value end-to-end encryption for notification content
  • You send notifications from many different scripts and don’t want to manage tokens

Pick Gotify If…

  • You want a web dashboard to view and organize all notifications
  • You want a plugin system for custom webhook receivers
  • You only use Android (iOS is a gap)
  • You prefer application-based organization over topic-based
  • You need long-term message storage in an external database (MySQL/PostgreSQL)
  • You want each notification source to have its own dedicated API token

Final Verdict

ntfy is the stronger choice for most self-hosters. The topic-based pub/sub model is simpler, the UnifiedPush support is a genuine differentiator, and the public cloud fallback at ntfy.sh means you still get notifications even when your server is offline. The iOS support, while imperfect (relay through ntfy.sh), puts it ahead of Gotify’s complete lack of official iOS support.

Gotify is not a bad app — its web dashboard is genuinely better for viewing notification history, and the plugin system adds extensibility that ntfy lacks. But the lack of UnifiedPush support and no iOS app limit its reach. If you’re Android-only and want a traditional dashboard experience, Gotify is solid. For everyone else, go with ntfy.