# How the Subscription and Premium Feature Gating System Works in Developer Roadmap

> Discover how kamranahmedse/developer-roadmap gates premium features using a React Query hook for real time subscription status and conditional UI rendering.

- Repository: [Kamran Ahmed/developer-roadmap](https://github.com/kamranahmedse/developer-roadmap)
- Tags: internals
- Published: 2026-02-24

---

**The developer-roadmap repository implements premium feature gating through a client-side React Query hook that polls a `/v1-billing-details` endpoint to determine subscription status, conditionally rendering UI components based on the `isPaidUser` boolean while managing upgrade flows via nanostores and Stripe checkout sessions.**

The subscription and premium feature gating system in the developer-roadmap repository controls access to advanced features like AI-powered roadmap generation and personalized learning paths. This React-based implementation relies on a coordinated architecture between a billing status API, React Query hooks for state management, and conditional component rendering to enforce access control entirely on the client side.

## Architecture Overview of the Premium Gating System

The system operates through four coordinated layers: a server-side billing endpoint that exposes subscription status, a React Query hook that caches and polls this data, UI components that gate features based on this state, and a nanostore-backed modal system that handles upgrade flows.

## Server-Side Billing Status Endpoint

### The /v1-billing-details API

The backend exposes a REST endpoint at `/v1-billing-details` that returns a JSON payload containing the user's subscription metadata. This includes the `status` field (indicating whether the subscription is "active"), along with `priceId` and `interval` information necessary for plan management and upgrade flows.

## Client-Side Subscription Detection with React Query

### The useIsPaidUser Hook

Located in [`src/queries/billing.ts`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/queries/billing.ts), the `useIsPaidUser` hook encapsulates the subscription detection logic. It uses React Query to poll the billing endpoint and derive a boolean flag indicating premium access.

```typescript
export function useIsPaidUser() {
  const { data, isLoading } = useQuery(
    { queryKey: ['billing-details'], queryFn: () => httpGet('/v1-billing-details'), enabled: !!isLoggedIn() },
    queryClient,
  );
  return { isPaidUser: data?.status === 'active', isLoading };
}

```

The hook only executes when `isLoggedIn()` returns true, preventing unnecessary API calls for anonymous users. It returns `isPaidUser: true` only when the subscription status equals "active", providing a reactive boolean that components can use for conditional rendering.

## Implementing Feature Gates in React Components

### Conditional Rendering Based on Subscription Status

UI components throughout the application import `useIsPaidUser` to determine whether to render premium features or upgrade prompts. This pattern appears in over 40 locations across the codebase, including roadmap generation, AI tutoring, and content creation features.

For example, in [`src/components/TopNavDropdowns/UpgradeProButton.tsx`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/components/TopNavDropdowns/UpgradeProButton.tsx), the component conditionally renders based on subscription status:

```tsx
const { isPaidUser, isLoading } = useIsPaidUser();
return isPaidUser ? null : <UpgradeButton disabled={isLoading} />;

```

This pattern ensures that premium UI elements are completely removed from the DOM for active subscribers, while non-subscribers see targeted upgrade prompts that trigger the purchase flow.

## Managing the Upgrade Flow

### Modal State Management with Nanostores

The application uses a lightweight nanostores store defined in [`src/stores/subscription.ts`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/stores/subscription.ts) to manage the upgrade modal's visibility state. This store provides a global boolean `isUpgradeModalOpen` and helper functions `showUpgradeModal()` and `hideUpgradeModal()` that any component can import to trigger the purchase interface without prop drilling.

### Stripe Checkout Integration

The premium landing page at [`src/components/Premium/PremiumPage.tsx`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/components/Premium/PremiumPage.tsx) handles the actual subscription creation through a React Query mutation. When a user selects a plan, the component calls the `/v1-create-subscription-checkout-session` endpoint and redirects to Stripe's hosted checkout page.

```tsx
import { useMutation } from '@tanstack/react-query';
import { httpPost } from '../../lib/query-http';

const { mutate: startCheckout } = useMutation(
  (priceId: string) => httpPost<{ checkoutUrl: string }>('/v1-create-subscription-checkout-session', { priceId }),
  {
    onSuccess: ({ checkoutUrl }) => (window.location.href = checkoutUrl),
    onError: (e) => console.error('checkout error', e),
  },
);

```

### Plan Switching for Existing Subscribers

For users with existing subscriptions who wish to change plans, the application renders an `UpdatePlanConfirmation` modal defined in [`src/components/Billing/UpdatePlanConfirmation.tsx`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/components/Billing/UpdatePlanConfirmation.tsx). This component calls the `/v1-update-subscription-plan` endpoint to modify the existing Stripe subscription without requiring the user to re-enter payment details.

## Post-Checkout Subscription Activation

After the user completes payment on Stripe's hosted page and returns to the application, the `useIsPaidUser` hook automatically refreshes the billing details cache. This reactive update instantly unlocks premium UI components across the application without requiring a page refresh, as React Query's background refetch detects the updated subscription status.

## Summary

- The subscription and premium feature gating system relies on a client-side architecture using React Query to poll `/v1-billing-details` and determine access rights.
- The `useIsPaidUser` hook in [`src/queries/billing.ts`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/queries/billing.ts) provides a reactive boolean flag that components use to conditionally render premium features or upgrade prompts.
- Over 40 UI components implement feature gating by checking `isPaidUser`, ensuring premium functionality is only accessible to active subscribers.
- The upgrade flow uses nanostores for modal state management and Stripe-hosted checkout via `/v1-create-subscription-checkout-session` to handle payments securely.
- Plan switching for existing subscribers is handled through `/v1-update-subscription-plan` without requiring new payment information.

## Frequently Asked Questions

### How does the developer-roadmap repository check if a user has an active subscription?

The repository uses the `useIsPaidUser` hook defined in [`src/queries/billing.ts`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/queries/billing.ts). This React Query hook polls the `/v1-billing-details` endpoint and returns `true` only when the subscription `status` field equals "active". Components throughout the application use this boolean to gate access to premium features.

### Is the premium feature gating implemented on the server or client side?

The gating is enforced entirely on the client side. While the server provides the billing status via the `/v1-billing-details` endpoint, the decision to render or hide premium UI components is made by React components checking the `isPaidUser` flag. This architecture relies on the server endpoint returning accurate subscription data while the UI handles the conditional rendering logic.

### How does the upgrade flow work when a user wants to purchase a premium plan?

The upgrade flow begins when a component calls `showUpgradeModal()` from the nanostores subscription store. The `PremiumPage` component in [`src/components/Premium/PremiumPage.tsx`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/components/Premium/PremiumPage.tsx) then renders pricing options, and selecting a plan triggers a mutation to `/v1-create-subscription-checkout-session`. Upon success, the user is redirected to Stripe's hosted checkout page. After payment completion, returning to the application triggers a refresh of the billing details, instantly unlocking premium features.

### Can existing subscribers change their subscription plan without canceling?

Yes, existing subscribers can switch plans through the `UpdatePlanConfirmation` modal component in [`src/components/Billing/UpdatePlanConfirmation.tsx`](https://github.com/kamranahmedse/developer-roadmap/blob/main/src/components/Billing/UpdatePlanConfirmation.tsx). When a user selects a different plan, the application calls the `/v1-update-subscription-plan` endpoint to modify the existing Stripe subscription. This process updates the subscription immediately without requiring the user to re-enter payment details or cancel their current plan first.