sly/notification-pusher
Send push notifications from Laravel through a single, unified API. Notification Pusher wraps multiple providers (Firebase Cloud Messaging, APNs, OneSignal and more) behind one clean interface, so you can swap services without rewriting code and keep your notification logic simple and testable.
Architecture fit. sly/notification-pusher is a standalone PHP library, not a Laravel-native package. It exposes a PushManager with pluggable adapters (historically APNS, GCM, MPNS) and a message/device abstraction. That adapter pattern is conceptually clean and can be bound into Laravel's service container via a thin service provider, but nothing about the package is Laravel-aware: no notification channel driver, no queue integration, no config publishing, no facade. It predates Laravel's first-party Notification system (5.3, 2016) and was designed to be framework-agnostic. Treat it as a transport library you must wrap, not a drop-in integration.
Integration feasibility. Wrapping is straightforward in principle — instantiate the manager, register adapters, push a collection of device tokens. The friction is almost entirely in the adapter layer, not the plumbing. In a Laravel codebase, the correct integration is to place it behind an internal PushSender interface so business logic and models never reference the package directly. That keeps the eventual swap cheap. Estimated effort for a production-grade wrapper (config, credentials, batching, logging, retry) is 3–5 engineer-days, with the real cost in token lifecycle work, not the binding.
Technical risk. This is the deciding factor and it is high.
Key questions to resolve before any commitment. (1) Which tagged version, and does it implement APNs HTTP/2 and FCM v1? (2) What PHP versions and dependency ranges does the Composer constraint allow against our runtime? (3) Is the APNs feedback / token-invalidation path implemented, or must we build it? (4) Who owns the fork if we vendor it? (5) Does it support concurrent/batched sends, or is it serial per message?
Stack fit. Poor for greenfield Laravel. On Laravel 5.3+ the idiomatic path is the built-in Notification system plus maintained channel packages (laravel-notification-channels/apn, .../fcm, or kreait/firebase-php for FCM v1). Those give queueing, channels, per-notifiable routing, and active maintenance for free. sly/notification-pusher is only defensible in three cases: a legacy non-Laravel PHP app, a Laravel 4.x/5.0–5.2 codebase, or a short-lived bridge during a platform migration.
Migration path. Do not adopt it as a terminal dependency. Sequence it as an interim transport:
App\Contracts\PushSender with send(Collection $tokens, PushMessage $msg): PushResult.NotificationPusherSender behind it — the only file that imports the package namespace.FcmV1Sender / ApnsHttp2Sender against the same contract, side by side.Compatibility. Verify PHP constraint and PSR compliance first — an older codebase may pull in PSR-0/PSR-2-era dependencies that conflict with a modern Laravel install's PSR-4/PSR-15 stack. Run composer why-not against your target runtime before writing any code. If it forces a dependency downgrade anywhere else in the tree, reject it immediately.
Sequencing. Week 1: protocol spike — prove a real push to a real device on both APNs and FCM v1 through the library. If that fails, stop; the package is non-viable regardless of stars. Week 2: wrapper, config, credential loading from the secret store. Week 3: queue integration, batching, structured logging of provider responses. Week 4: token lifecycle (prune on APNs 410 / FCM UNREGISTERED). Only then consider shadow-mode traffic.
Maintenance. Effectively unmaintained. Assume you own the code: vendor it, pin the commit, and budget for a fork. Dependency scanners will raise noise, and there will be no upstream patch if a provider changes an endpoint — which is exactly the failure mode that killed GCM support here. Add it to the "owned forks" register with a named maintainer.
Support. Community-only, stale issues, no SLA. Escalation for a production push outage is internal. This is acceptable for a 4-week bridge, unacceptable for a multi-year platform dependency.
Scaling. Push fan-out is I/O-bound, not CPU-bound, so the library's own throughput is rarely the bottleneck — your queue topology is. Requirements the package does not solve for you: worker concurrency limits, provider rate limits (APNs returns 429 and expects connection reuse; FCM v1 enforces per-project quotas), batching (APNs caps payload size and benefits from multiplexed streams), exponential backoff with jitter, and dead-letter handling. Plan on Redis/SQS-backed workers with a dedicated push queue, separate from user-facing queues.
Failure modes to instrument. Expired or rotated credentials (silent auth failures returning 403); unregistered tokens accumulating because feedback pruning was never wired up; oversized payloads rejected per-token; partial batch failures where a naive implementation marks the whole batch failed; provider 5xx during bursts; and clock skew breaking JWT-based APNs auth. Every one of these must emit a metric, because push failures are otherwise invisible — the user simply doesn't get notified.
Ramp-up. API surface is small; a mid-level engineer is productive in a day. The genuine ramp-up cost is domain knowledge: APNs vs. FCM semantics, token lifecycle, payload constraints, and per-platform behavior differences. Budget two to three days of reading and device testing per engineer, and require physical-device verification — simulators and emulators routinely mask token and entitlement problems.
Recommendation. Do not adopt for new work. Use it only as a time-boxed migration bridge behind a stable internal interface, with a dated exit criterion and an allocated owner. The star count reflects 2014-era relevance; zero dependents and dead upstream protocols reflect its actual risk today.
How can I help you explore Laravel packages today?