The ixartz SaaS-Boilerplate is one of the most starred open-source SaaS starters on GitHub with over 6,800 stars. It's built with Next.js, Clerk, Drizzle ORM, and Tailwind CSS — a modern stack for building multi-tenant SaaS applications.
We ran it through a comprehensive PLG skills audit — analyzing signup flow CRO, feature gating, trial optimization, product analytics, self-serve motion, and paywall design.
Overall PLG score: 3/10 — Excellent foundation for auth and multi-tenancy, but PLG features like checkout, trials, and analytics are explicitly marked as "PRO" features.
The full audit
| Category | Score | Key finding |
|---|---|---|
| Signup flow | 7/10 | Clerk integration with OAuth, magic link, multi-locale |
| Feature gating | 3/10 | Role-based access exists, but no plan-based gating |
| Trial optimization | 0/10 | No trial period tracking or logic |
| Product analytics | 2/10 | Sentry for errors only — no product analytics |
| Self-serve motion | 4/10 | Pricing UI exists, but checkout is PRO-only |
| Paywall/upgrade CRO | 2/10 | Static pricing page, no in-app upgrade prompts |
1. Signup flow analysis
What's implemented
The signup delegates entirely to Clerk's hosted components:
// src/app/[locale]/(auth)/(center)/sign-up/[[...sign-up]]/page.tsx
import { SignUp } from '@clerk/nextjs';
const SignUpPage = (props: { params: { locale: string } }) => (
<SignUp path={getI18nPath('/sign-up', props.params.locale)} />
);
Authentication options:
- Email + password via Clerk
- OAuth providers (Google, GitHub configurable)
- Magic link support
- Multi-locale support (en, fr)
The middleware handles Clerk session validation:
// src/middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/:locale/dashboard(.*)',
]);
What's missing
No custom signup form. You're locked into Clerk's UI and can't customize fields or add progressive profiling.
No signup analytics. No tracking events for:
- Signup page viewed
- Signup started
- Signup completed
- Email verified
2. Feature gating audit
What's implemented
Role-based access control with organization roles:
// src/types/Auth.ts
export const ORG_ROLE = {
ADMIN: 'org:admin',
MEMBER: 'org:member',
} as const;
export const ORG_PERMISSION = {
// Add Organization Permissions here
} as const;
A ProtectFallback component exists for locked features:
// src/features/auth/ProtectFallback.tsx
export const ProtectFallback = (props: { trigger: React.ReactNode }) => {
return (
<Tooltip>
<TooltipTrigger asChild>{props.trigger}</TooltipTrigger>
<TooltipContent>
<p>{t('not_enough_permission')}</p>
</TooltipContent>
</Tooltip>
);
};
What's missing
No plan-based gating. The ORG_PERMISSION object is empty — no actual permissions are implemented.
Missing components:
- No
hasFeature()orcanAccess()utility functions - No subscription tier checks
- No usage limit enforcement
- No upgrade prompts when limits are reached
3. Trial optimization
What's implemented
The database schema includes Stripe subscription fields:
-- src/migrations/0000_init-db.sql
CREATE TABLE IF NOT EXISTS "organization" (
"stripe_subscription_status" text,
"stripe_subscription_current_period_end" bigint,
...
);
What's missing
Trials are completely absent:
- No
trial_period,trial_end, ortrial_started_atfields - No trial status enums
- No trial email sequences
- No trial countdown UI
- No trial-to-paid conversion logic
4. Product analytics
What's implemented
Sentry for error monitoring only:
// src/instrumentation.ts
import * as Sentry from '@sentry/nextjs';
export async function register() {
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1,
});
}
Logtail for structured logging:
// src/libs/Logger.ts
if (Env.LOGTAIL_SOURCE_TOKEN) {
stream = pino.multistream([
await logtail({ sourceToken: Env.LOGTAIL_SOURCE_TOKEN }),
]);
}
What's missing
No product analytics provider:
- No PostHog, Mixpanel, Amplitude, Segment, or GA4
- No
.track()or.capture()calls - No user identification
- No feature usage tracking
- No funnel analytics
Impact: You cannot measure signup-to-paid conversion, time-to-first-payment, or feature adoption.
5. Self-serve motion
What's implemented
Pricing configuration with three tiers:
// src/utils/AppConfig.ts
export const PricingPlanList: Record<string, PricingPlan> = {
[PLAN_ID.FREE]: {
price: 0,
features: { teamMember: 2, website: 2, storage: 2, transfer: 2 },
},
[PLAN_ID.PREMIUM]: {
price: 79,
devPriceId: 'price_1PNksvKOp3DEwzQlGOXO7YBK',
features: { teamMember: 5, website: 5, storage: 5, transfer: 5 },
},
[PLAN_ID.ENTERPRISE]: {
price: 199,
features: { teamMember: -1, website: -1, storage: -1, transfer: -1 },
},
};
Pricing UI components exist for displaying plans.
What's missing
Checkout is explicitly a PRO feature:
// src/types/Subscription.ts comment
// PricingPlan is currently only used for Pricing section of the landing page.
// If you need a real Stripe subscription payment with checkout page,
// customer portal, webhook, etc. You can check out the Next.js Boilerplate Pro
Missing self-serve components:
- No Stripe checkout session creation
- No payment processing endpoint
- No customer portal integration
- No webhook handlers
- No upgrade/downgrade flow
6. Paywall and upgrade CRO
What's implemented
Static pricing page with feature comparison:
// src/templates/Pricing.tsx
<PricingInformation
buttonList={{
[PLAN_ID.FREE]: (
<Link href="/sign-up">{t('button_text')}</Link>
),
[PLAN_ID.PREMIUM]: (
<Link href="/sign-up">{t('button_text')}</Link>
),
}}
/>
Note: All pricing buttons just link to signup — no checkout flow.
What's missing
No in-app upgrade prompts:
- No "upgrade now" buttons in dashboard
- No usage limit displays
- No locked feature prompts with upgrade CTAs
- No billing page (commented as PRO feature)
Database schema
The schema is well-structured for multi-tenancy:
| Table | Purpose |
|---|---|
organization | Multi-tenant workspaces with Stripe fields |
organization_membership | User-to-org relationships with roles |
Missing tables for PLG:
- No
usage_metricsorfeature_usage - No
trial_statustracking - No
subscription_eventsaudit log
What you need to add
Priority 1: Checkout flow (critical)
You'll need to implement Stripe checkout yourself or upgrade to the PRO version:
// Example implementation needed
export async function createCheckoutSession(priceId: string) {
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [{ price: priceId, quantity: 1 }],
success_url: '/dashboard',
cancel_url: '/pricing',
});
return session;
}
Priority 2: Analytics
Add PostHog or Mixpanel. Track at minimum:
track('signup_completed')
track('pricing_page_viewed')
track('checkout_started', { plan: 'premium' })
track('checkout_completed', { plan: 'premium' })
Priority 3: Feature gating
Implement the empty ORG_PERMISSION object with actual plan-based checks:
function canAccess(user, feature) {
const plan = user.organization?.subscription_plan;
return PLAN_FEATURES[plan]?.includes(feature);
}
First steps to PLG
ixartz gives you great multi-tenancy — here's how to add PLG on top:
Week 1: Decide build vs buy
The free version has no checkout. Your options:
- Buy PRO version — includes Stripe checkout, portal, webhooks
- Build yourself — add Stripe from scratch (2-3 days work)
- Use Paddle/Lemon Squeezy — simpler alternative to Stripe
If building yourself, start with a single "Pro" plan before adding tiers.
Week 2: Add analytics
- Install PostHog:
npm install posthog-js - Add provider in your root layout
- Use Clerk's user ID for
posthog.identify() - Track:
signup_completed,org_created,checkout_started,subscription_activated
Week 3: Populate the permissions
The ORG_PERMISSION object is empty. Fill it in:
export const ORG_PERMISSION = {
VIEW_ANALYTICS: 'org:view_analytics',
EXPORT_DATA: 'org:export_data',
MANAGE_BILLING: 'org:manage_billing',
} as const;
// Map to plans
const PLAN_PERMISSIONS = {
free: [ORG_PERMISSION.VIEW_ANALYTICS],
pro: [ORG_PERMISSION.VIEW_ANALYTICS, ORG_PERMISSION.EXPORT_DATA],
enterprise: Object.values(ORG_PERMISSION),
};
Week 4: Add upgrade prompts
When users hit permission checks:
{canAccess(user, 'export_data') ? (
<ExportButton />
) : (
<UpgradeCard feature="Data Export" plan="Pro" />
)}
Key metrics to track
- Organizations created per week
- Time from org creation to first paid subscription
- Feature adoption by plan (which pro features get used?)
- Upgrade conversion rate from upgrade prompts
When to use this template
Good fit:
- You want a solid multi-tenant foundation with Clerk
- You're okay building checkout and analytics yourself
- You need i18n support out of the box
Not ideal:
- You need PLG features immediately
- You want to avoid building Stripe integration from scratch
- You need product analytics without additional work
Conclusion
The ixartz SaaS-Boilerplate scores 3/10 for PLG readiness. It's an excellent foundation for multi-tenant SaaS with modern tooling (Next.js 14, Clerk, Drizzle), but the free version is explicitly designed as a starting point — not a complete PLG solution.
The core PLG features (checkout, customer portal, webhooks, dark mode) are reserved for the paid PRO version. If you're building a PLG SaaS, you'll either need to:
- Build the monetization layer yourself
- Purchase the PRO version
- Use a different boilerplate with these features included
Frequently asked questions
Is the ixartz SaaS-Boilerplate really free?
The base version is free and open-source under MIT license. However, Stripe checkout, customer portal, dark mode, and billing management are "PRO" features that require purchasing the paid version.
Does it include Stripe integration?
The database schema includes Stripe fields, and pricing UI exists, but actual payment processing is not implemented in the free version. The code comments explicitly say to "check out the Next.js Boilerplate Pro" for checkout and webhooks.
How does it compare to other SaaS starters?
It has the strongest multi-tenant and i18n foundation of the open-source options, but the weakest PLG features. BoxyHQ and Saasfly include working Stripe checkout in their free versions.
Should I use Clerk for authentication?
Clerk simplifies auth significantly but locks you into their hosted UI. If you need custom signup forms or analytics on the signup flow, you may want more flexibility.
This analysis was performed using PLG Skills, an open-source framework for product-led growth audits. Skills used: signup-flow-cro, feature-gating, trial-optimization, product-analytics, self-serve-motion, paywall-upgrade-cro.