Drop-in paywall infrastructure for Next.js apps
Add Stripe subscriptions in minutes. Works with any auth provider (NextAuth, Clerk, Lucia, Supabase, etc.).
<MilkieProvider email={session.user.email}>
<PaywallGate>
<PremiumContent />
</PaywallGate>
</MilkieProvider>That's it. Your content is now behind a paywall.
- π Subscription Gating -
<PaywallGate>for premium content - πͺ Auth Gating -
<AuthGate>for authenticated-only content - π¨ Fully Customizable - Custom UIs, messaging, styling
- π Security Built-In - Callback validation, idempotency, PII sanitization
- π Auth-Agnostic - Works with NextAuth, Clerk, Lucia, Supabase, etc.
- β‘ 3 API Routes - That's all you need on the backend
- Sign in with Google
- Try the gated examples (Component Gating or Layout Gating)
- See the paywall with built-in checkout flow
- Subscribe with test card:
4242 4242 4242 4242 - Content unlocked!
v0.4.0 - Production Ready β
Fully functional:
- β Stripe checkout & subscription management
- β Real-time webhook handling
- β Auth-agnostic design (works with any auth provider)
- β
Subscription gating with
<PaywallGate> - β
Authentication gating with
<AuthGate> - β Component-level and layout-level gating patterns
- β Smart sign-in redirects with callback URLs
- β Fully customizable UIs, messaging, and styling
- β Built-in blurred content previews
- β Toast notifications for errors
- β Security features (callback validation, idempotency, PII sanitization)
On the roadmap:
- π’ Multi-tenancy support
- π Developer dashboard
- π Webhook relay service for local development
- ποΈ Multiple subscription tiers
npm install milkie3 steps to add paywalls:
- Create 3 API routes (guide)
- Wrap your app:
<MilkieProvider email={session?.user?.email}> - Gate content:
<PaywallGate><PremiumContent /></PaywallGate>
See: QUICKSTART.md for detailed setup or try the demo
Getting Started:
- QUICKSTART.md - Setup guide + run demo locally
- Backend Setup - API routes and database adapters
- Auth Integration - Works with any provider
Implementation:
- 7 Paywall Patterns - Component gating, metered access, custom checkout
- API Reference - Components, props, hooks
- Customization - Styling and custom UI
- Best Practices - Production deployment
Protect premium content behind a subscription paywall:
import { PaywallGate } from "milkie";
<PaywallGate>
<PremiumContent />
</PaywallGate>;What happens:
- Unauthenticated users see a sign-in prompt
- Authenticated users without subscription see the paywall with checkout
- Subscribers see the content
Customization options:
<PaywallGate
title="Unlock Premium Features"
subtitle="Get access to all premium content"
subscribeButtonLabel="Upgrade Now"
showBlurredChildren={true} // Show blurred preview of content
overlayClassName="items-start pt-20" // Custom positioning
/>Require sign-in without requiring a subscription:
import { AuthGate } from "milkie";
<AuthGate>
<AuthenticatedContent />
</AuthGate>;What happens:
- Unauthenticated users see a sign-in prompt
- Authenticated users see the content (no subscription required)
Customization options:
<AuthGate
title="Sign in to continue"
subtitle="Access your account"
signInButtonLabel="Sign In"
showBlurredChildren={false} // No blur, just show the overlay
/>For complete control over your paywall logic:
import { usePaywall } from "milkie";
function CustomComponent() {
const { hasAccess, loading, status, email } = usePaywall();
if (loading) return <LoadingSpinner />;
if (!hasAccess) return <YourCustomPaywall />;
return <PremiumContent />;
}Available from the hook:
hasAccess- boolean indicating subscription statusloading- boolean for loading statestatus- Stripe subscription status stringemail- user email from providererror- error message if anycheckSubscription()- manually refresh subscription statusclearError()- clear error state
Milkie is designed to be fully customizable to match your app's design.
Tailor the paywall messaging to your brand:
<PaywallGate
title="Upgrade to Pro"
subtitle="Get unlimited access to all features"
subscribeButtonLabel="Start Free Trial"
signInButtonLabel="Sign in to subscribe"
/>Position the paywall card anywhere on the page:
// Top of page
<PaywallGate overlayClassName="items-start pt-20" />
// Bottom of page
<PaywallGate overlayClassName="items-end pb-20" />
// Left side
<PaywallGate overlayClassName="justify-start pl-20" />The overlayClassName accepts any Tailwind CSS classes. The overlay is placed in a CSS Grid container with items-center justify-items-center by default, so you can use alignment classes like items-start, items-end, justify-items-start, or justify-items-end to reposition it.
Replace the entire paywall card with your own component:
import { usePaywall } from "milkie";
function YourCustomPaywall() {
const { email, loading } = usePaywall();
// Your custom logic and UI
}
<PaywallGate customUi={<YourCustomPaywall />} />;With customUi, you have complete control over the paywall appearance and behavior.
See all customization options: packages/react/README.md
Milkie includes production-ready security protections:
- Callback URL Validation - Prevents open redirect attacks by validating redirect URLs
- Idempotency Keys - Prevents duplicate Stripe checkout sessions and charges
- PII Sanitization - Removes sensitive data from error logs
- Webhook Signature Verification - Validates Stripe webhook signatures
- Email Normalization - Consistent email handling across the system
These security features are built-in and active by default.
Adding subscriptions shouldn't take 2 days. Here's what Milkie handles for you:
What you'd normally build:
- β Stripe checkout session creation
- β Webhook endpoint configuration
- β Subscription status tracking
- β Access control logic
- β Paywall UI components
- β Error handling and edge cases
With Milkie:
- β
Wrap your content with
<PaywallGate> - β That's it
Time saved: Days β Minutes
Demo app:
- Next.js 15 with App Router
- TypeScript
- NextAuth.js (Google OAuth)
- Stripe Checkout & Webhooks
- Drizzle ORM with PostgreSQL
- Tailwind CSS + shadcn/ui
- Sonner (toast notifications)
Package: (milkie)
- Published on npm
- React Context for state management
- Factory functions for API routes
- Database-agnostic adapters
- TypeScript for type safety
milkie/
βββ LICENSE # MIT License
βββ README.md # You are here
βββ QUICKSTART.md # Get running in 15 min
βββ packages/
β βββ react/ # milkie npm package (v0.1.0)
β βββ src/
β β βββ provider.tsx # MilkieProvider & usePaywall hook
β β βββ paywall-gate/ # PaywallGate component
β β β βββ components/
β β β βββ paywall-card.tsx
β β β βββ user-info.tsx
β β β βββ checkout-error.tsx
β β βββ auth-gate/ # AuthGate component
β β β βββ components/
β β β βββ auth-card.tsx
β β βββ components/ # Shared components
β β β βββ loading-state.tsx
β β β βββ blurred-content.tsx
β β β βββ overlay-grid.tsx
β β β βββ milkie-icon.tsx
β β β βββ ui/ # shadcn/ui components
β β βββ api/ # Factory functions for routes
β β βββ subscription.ts # createSubscriptionStatusRoute
β β βββ checkout.ts # createCheckoutRoute
β β βββ webhooks.ts # createWebhookRoute
β βββ README.md # Package documentation
βββ docs/
β βββ BACKEND_SETUP.md # Complete backend guide
β βββ AUTH_INTEGRATION.md # Works with any auth
β βββ IMPLEMENTATION_GUIDE.md # Complete guide with 7 paywall patterns
β βββ paywall-patterns/ # Detailed pattern docs
β βββ reference/ # API docs, customization, best practices
βββ demo/ # Working demo app
βββ .env.example # Environment variables template
βββ app/ # Next.js app directory
β βββ page.tsx # Public homepage
β βββ mixed/ # Component-level gating example
β βββ premium/ # Full-page gating example
β βββ dashboard/ # Layout-level gating example
β βββ api/ # API routes (using milkie factories)
β βββ checkout/ # Stripe checkout session
β βββ subscription/ # Subscription status check
β βββ webhooks/ # Stripe webhook handler
βββ lib/
β βββ milkie-adapter.ts # Database adapters for milkie
β βββ db/ # Database schema & client
β βββ stripe.ts # Stripe configuration
βββ auth.ts # NextAuth configuration
- Try the demo - See it in action
- Install the package -
npm install milkie - Set up backend - 3 API routes
- Integrate with your auth - Works with any provider
- Learn the patterns - Component gating, metered paywalls, custom checkout, and more
This is an early-stage project. Feedback is incredibly valuable!
Open an issue if you:
- Find bugs or unexpected behavior
- Have feature requests or ideas
- Want to discuss the implementation approach
- Would actually use this for your projects
MIT