I built a posthumous messaging app called LastSend. Users create messages (text, photos, videos, voice recordings, documents) that get delivered to loved ones after they pass away. The Android app is live on Google Play.
The interesting part: the entire backend runs on n8n.
The setup
Self-hosted n8n in queue mode on a Hetzner VPS. Docker Compose with PostgreSQL, Redis, n8n main instance, n8n worker, and Caddy for reverse proxy. Currently running 40+ active workflows.
What n8n handles
-
Payments: Google Play Billing verification and PayPal webhook processing. When a user subscribes on Android, Google sends a webhook to n8n, which verifies the purchase token against the Google Play API, updates the user’s subscription status in Supabase, and triggers the appropriate access changes.
-
Media processing: Users upload photos, videos, voice recordings, and documents. n8n workflows handle the processing pipeline - image optimization with sharp, video processing with ffmpeg, generating thumbnails, and storing everything in Cloudflare R2 via presigned URLs.
-
Push notifications: Firebase FCM integration for Android push notifications. Workflows manage check-in reminders, trusted contact alerts, and system notifications.
-
Subscription lifecycle: The full subscription state machine - trial periods, upgrades, downgrades, cancellations, grace periods, and expired account handling.
-
Trusted contact system: When a user misses their check-ins, n8n triggers an escalation flow. Trusted contacts get notified, and there’s a multi-step verification process before any messages get delivered.
-
Account cleanup: A 15-day automated pipeline for deceased accounts. Handles message delivery scheduling, media access for recipients, memorial page creation, and eventually cleans up storage.
What I learned
-
Queue mode is essential once you have more than 10-15 workflows. Execution mode was hitting memory limits and dropping webhook events.
-
Sub-workflows for everything reusable. I have shared sub-workflows for things like “send push notification”, “update subscription status”, “process media file” that multiple parent workflows call.
-
Error handling can’t be an afterthought. Every workflow that touches external APIs (Google Play, PayPal, Cloudflare, Firebase) has retry logic and error notification sub-workflows. Payment webhooks especially - if those fail silently, users lose access they paid for.
-
Native nodes first, Code nodes as last resort. I only use Code nodes when the native node genuinely can’t do what I need. Keeps workflows readable and maintainable.
If anyone has questions about running n8n at this scale or specific patterns I used, happy to share more.