// Advertisement

Next JS SaaS Boilerplate Unpacked: Core Features Explained

published on 06 December 2023

Most website owners would likely agree:

Setting up a modern, feature-rich SaaS platform from scratch is an extremely challenging undertaking.

However, by leveraging a thoughtfully-designed Next.js boilerplate tailored for SaaS products, you can kickstart development and rapidly build an impressive multi-tenant web app.

In this post, we'll unpack the key components powering Next.js SaaS starter kits, like authentication flows, database architecture, routing, and more - with actionable code snippets to guide your understanding.

Introduction to Next.js SaaS Boilerplates

A Next.js SaaS boilerplate provides a pre-configured foundation for building a multi-tenant SaaS (Software-as-a-Service) application using the Next.js React framework. These boilerplates include authentication, database integration, API routes, and other essential features required for SaaS products out-of-the-box, allowing developers to skip repetitive setup tasks and start building core app functionality faster.

In this article, we’ll break down everything you need to know about Next.js SaaS boilerplates, including:

What is a Next.js SaaS Boilerplate?

A Next.js SaaS boilerplate is a starter project template engineered specifically for developing multi-tenant SaaS apps with Next.js.

These boilerplates come pre-loaded with:

  • Authentication - Handles user signup, login, forgot password workflows. Often using NextAuth.js.
  • Database - MySQL, MongoDB, Prisma integrations. Handles multi-tenancy models.
  • API Routes - Pre-built CRUD APIs for managing users, subscriptions data.
  • UI Components - Complete admin dashboard, subscription pages, etc.
  • Helpers - Utilities for access control, usage analytics, payments and more.

Together these features provide a complete full-stack starting point for any SaaS product built with Next.js and React. Developers can clone the boilerplate codebase and start coding app-specific features without reinventing the wheel on complex SaaS functionality.

The Perks of a Free React SaaS Boilerplate

Free open-source Next.js SaaS boilerplates offer many advantages over starting SaaS projects from scratch:

  • Rapid Onboarding - Get up and running in minutes instead of weeks.
  • Best Practices - Leverages proven code patterns for scalability.
  • Time Savings - Avoid developing repetitive platform-level features.
  • Lower Costs - Reduce initial dev resources needed.
  • Customizable - Open-source code can be adapted to specific needs.

For lean teams and startups, a free boilerplate kickstarts development and allows focusing effort on creating value for customers. The availability of well-structured open-source SaaS starters is a huge win for the React ecosystem.

Key Components of a Next JS SaaS Template

While features vary across boilerplates, most Next.js SaaS templates provide a standard set of functions:

Multi-Tenant Data Model

// Example schema handling data separation  
const User = {
  id: string
  tenantId: string
}

const Tenant = { 
  id: string
  name: string
  // tenant data
} 

This separates user & tenant data, enabling support for multiple customer accounts within one codebase.

Authentication Scaffolding

Handles signup, login, access control, and exposing user/tenant info to pages via hooks like useSession().

Dashboards & Admin UI

Pre-built interfaces for managing subscribers, viewing usage analytics, editing tenant data and more.

API Functions

CRUD APIs for database entities users, tenants, subscriptions etc. following REST/RPC convention.

Payments Integration

Helpers for managing subscriptions via Stripe, Braintree and other payment gateways.

In summary, Next.js SaaS boilerplates are integral for quickly building robust, scalable SaaS applications with React. They provide startups and developers a solid, mature architecture out-of-the-box to iterate on rather than reinventing solutions for common SaaS requirements.

Authentication and User Management in SaaS

Authentication is crucial for any SaaS application to manage access and protect user data. Let's explore some key elements of implementing robust auth in a Next js SaaS boilerplate.

Setting Up Secure Sessions with JWT

JSON Web Tokens (JWTs) enable secure user sessions in Node.js apps. Here's an example using the jsonwebtoken library to generate signed JWTs:

import jwt from 'jsonwebtoken';

// Create a signed JWT 
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '1d' }); 

// Attach JWT to response
res.json({ token });

The Next js SaaS boilerplate handles JWT creation behind the scenes when users register or log in. The token contains the user ID and role data for authorization.

To integrate JWT sessions:

  • Store the encrypted token in HTTPOnly cookies
  • Validate the JWT on protected API routes and pages
  • Destroy cookie on logout to enforce session expiration

This enables a secure, stateless user session system.

Crafting Custom Login and Signup Flows

A Next js SaaS template offers pre-built login and signup UIs. But we can craft custom experiences using Next.js pages and API routes.

For example, here's a login API route handling email/password authentication:

// [...nextauth].js 

export default async (req, res) => {

  const { email, password } = req.body;

  try {
    const user = await auth.authenticate({ email, password });

    const token = generateJWT(user); 
    
    res.status(200).json({ token });

  } catch (error) {
    res.status(400).json({ message: 'Invalid credentials' });
  }

}

We could call this API route from a custom Login page component to initialize sessions.

The Next js SaaS boilerplate source code provides examples of customizable auth flows like this.

Implementing Role-based Access Control

Role-based access control (RBAC) restricts access to pages and API routes based on the user's role.

For example, only admin users may access a Tenant Management page:

export default function TenantPage() {

  const { user } = useAuth();

  // Check if user role is "admin"
  if (user.role !== 'admin') {
    return <Unauthorized />
  }

  return <TenantManagementDashboard />

}

And the createTenant API could be limited to admin users:

// pages/api/tenants.js
export default async (req, res) => {

  const { user } = await auth.validate(req);

  // Restrict access if user isn't an admin 
  if (user.role !== 'admin') {
    return res.status(403).end();
  }

  // Create new tenant
  const tenant = await Tenant.create(req.body);
  
  res.status(201).json(tenant);

}

The multi tenant SaaS boilerplate templates provide RBAC wrappers to easily enforce permissions.

This ensures users only access resources they are authorized for based on their role. Critical for secure SaaS applications.

Multi-Tenant Database Architecture

We'll explore the boilerplate's MongoDB schema and models for supporting multiple tenants in a SaaS environment.

Exploring the Multi-Tenant Database Schema

The boilerplate uses MongoDB to store user, tenant, and application data. There are separate collections for users, tenants, and each tenant's data.

Here is an example document structure:

Users Collection
{
  _id: ObjectId, 
  name: string,
  email: string
  // other user fields  
}

Tenants Collection 
{
  _id: ObjectId,
  name: string, 
  ownerId: ObjectId // Reference to user _id
  // Tenant fields
}

Tenant Data Collection
{
  _id: ObjectId,
  tenantId: ObjectId // Reference to tenant _id
  // Application data fields  
}

This structure keeps user and tenant information separate from the protected application data for each tenant. The tenantId field links each data document to the appropriate tenant.

Strategies for Modeling Tenants

There are a few common ways to model multi-tenant data:

  • Separate Databases: Give each tenant their own logical database. Simple but doesn't scale well.
  • Shared Database, Separate Collections: Use separate collections for each tenant's data like the boilerplate example above.
  • Shared Database, Shared Collection: Store all tenant data in one collection and filter by the tenantId field.

The boilerplate uses separate collections since it makes access control and data isolation easier compared to a shared collection.

Querying and Aggregating Multi-Tenant Data

When querying, we filter by the tenantId to only return a tenant's data:

TenantData.find({ tenantId: tenant._id })

Aggregation works the same way. To get metrics for a tenant, filter on tenantId first:

TenantData.aggregate([
    { $match: { tenantId: tenant._id } },
    {
      $group: {
        _id: null,
        count: { $sum: 1 }  
      }
    }
])  

This ensures tenants only access their own data. The boilerplate handles permissions automatically based on the currently logged in user.

{

"header": "Multi-Tenant Database Architecture", "context": "We'll explore the boilerplate's MongoDB schema and models for supporting multiple tenants in a SaaS environment.", "sub_headers": [ { "header": "Exploring the Multi-Tenant Database Schema", "context": "The document model and relationship between users, tenants, and data within a multi tenant SaaS boilerplate." }, { "header": "Strategies for Modeling Tenants", "context": "Best practices for managing data isolation and separation for different customer accounts in a multi-tenant architecture." }, { "header": "Querying and Aggregating Multi-Tenant Data", "context": "Effective database operations for a multi-tenant context, with examples from a Next js SaaS boilerplate example." } ], "contentSize": "long" }

Exploring the Multi-Tenant Database Schema

The boilerplate uses MongoDB to store user, tenant, and application data. There are separate collections for users, tenants, and each tenant's data.

Here is an example document structure:

Users Collection
{
  _id: ObjectId, 
  name: string,
  email: string
  // other user fields  
}

Tenants Collection 
{
  _id: ObjectId,
  name: string, 
  ownerId: ObjectId // Reference to user _id
  // Tenant fields
}

Tenant Data Collection
{
  _id: ObjectId,
  tenantId: ObjectId // Reference to tenant _id
  // Application data fields  
}

This structure keeps user and tenant information separate from the protected application data for each tenant. The tenantId field links each data document to the appropriate tenant.

Strategies for Modeling Tenants

There are a few common ways to model multi-tenant data:

  • Separate Databases: Give each tenant their own logical database. Simple but doesn't scale well.
  • Shared Database, Separate Collections: Use separate collections for each tenant's data like the boilerplate example above.
  • Shared Database, Shared Collection: Store all tenant data in one collection and filter by the tenantId field.

The boilerplate uses separate collections since it makes access control and data isolation easier compared to a shared collection.

Querying and Aggregating Multi-Tenant Data

When querying, we filter by the tenantId to only return a tenant's data:

TenantData.find({ tenantId: tenant._id }) 

Aggregation works the same way. To get metrics for a tenant, filter on tenantId first:

TenantData.aggregate([
  { $match: { tenantId: tenant._id } }, 
  {
    $group: {
      _id: null,
      count: { $sum: 1 }   
    }
  }
])

This ensures tenants only access their own data. The boilerplate handles permissions automatically based on the currently logged in user.

sbb-itb-5683811

Server-Side Routing and Multi-Tenancy

How routing works in Next.js SaaS apps and how it enforces tenant separation.

Tenant-Specific [tenantId] Dynamic Routing

The [tenantId] pattern in Next.js allows creating tenant-aware pages and API routes. By parsing the tenant ID from the request url, we can query data scoped to that tenant from the database.

For example:

pages/app/[tenantId]/dashboard.js

export async function getServerSideProps({ params }) {

  const { tenantId } = params

  // fetch tenant data

  return {
    props: {
      tenant: tenantData
    }
  }
}

Now when users visit /app/tenantA/dashboard or /app/tenantB/dashboard, they will see dashboard data specific to that tenant.

This keeps tenant data isolated in a multi-tenant SaaS app built with Next.js.

Securing Public vs Private Routes

Next JS SaaS boilerplates handle authentication and authorization to show/hide pages and API routes based on login status.

Public pages like /login and /register are accessible to everyone. But private pages are protected by Higher Order Components (HOCs):

// Auth HOC

import { useUser } from '@auth0/nextjs-auth0';

export default function withAuth(Component) {

  return props => {

    const { user } = useUser();

    if (!user) {
      return <Login />
    }

    return <Component {...props} />

  }

}

Now wrapping components with this HOC checks if a user exists, and redirects to login if not. This pattern secures dashboards, account pages, etc. in any Next.js SaaS app.

Optimizing with Code Splitting and Dynamic Imports

Large Next.js apps can improve performance by splitting code into separate bundles that load on-demand.

Features like:

  • Dynamic component imports
  • Dynamic API routes
  • Disabling static optimization

Allow loading page modules only when needed.

For example:

// pages/app/[tenantId]/dashboard.js

import dynamic from 'next/dynamic'

const Analytics = dynamic(() => import('../components/Analytics'))

export default function Dashboard() {

  return (
    <>
      <h1>Dashboard</h1>
      <Analytics />
    </>
  )

}

Now the Analytics component is bundled separately and loads when this page is rendered. This code splitting optimizes delivery of Next.js SaaS pages.

So in summary, Next.js handles critical needs for SaaS: isolated tenant data, secured resources, and performance. These capabilities make it a strong choice for building multi-tenant web apps.

Customizable UI and Theming for SaaS

Easily adapting the boilerplate styling and layout to your brand's needs.

Tailoring Modular SCSS Styling

When building a SaaS product, having full control over the look and feel is key for crafting a unique brand identity. The Next JS SaaS boilerplate example provides a robust SCSS architecture that makes it simple to customize styles.

It implements a modular approach, separating color variables, typography, components, and more into independent files. Tweaking something like the primary color palette cascade changes across all elements instantly.

// Example _variables.scss

$primary: #2196F3;
$secondary: #FFF176;

This structure ensures minimal overhead when adapting styles to your needs, allowing quick iterations without side effects.

Beyond colors, modify typography, border-radius, shadows, etc. for your preferred aesthetic. Customize individual component scopes too, e.g. buttons, cards, form elements.

// Example _buttons.scss

.button {
  padding: 12px 24px; 
  border-radius: 8px;
  
  &.primary {
    background: $primary;
  }
}

Thanks to SCSS nesting and variables, theme changes propagate easily. This modular architecture empowers designing a unique brand style for your SaaS efficiently.

Mastering Layout and Views Customization

Crafting a consistent user experience across a SaaS platform requires controlling layouts and views in one place.

The NextJS SaaS boilerplate provides reusable React layout components to wrap pages and sections. This enables globally configuring the chrome and structure wrapping around inner content.

// Example Layout.js

export default ({children}) => {
  return (
    <div className="layout">
      <Header />
      <Sidebar />
      
      <main>{children}</main>
      
      <Footer />
    </div>
  )
}

Any page leveraging this Layout component automatically inherits its consistent header, sidebar, and footer. Customizing those once then applies changes everywhere.

For view primitives, abstractions like Page and Section encapsulate styling into reusable building blocks.

// Example Page.js

export default ({title, children}) => {
  return (
    <article>
      <h1>{title}</h1>
      
      <section>{children}</section>
    </article>
  )
}

Composing these constructs guarantees UI consistency, while allowing global control. This simplifies theming dramatically compared to modifying templates individually.

Overall, the boilerplate architecture here empowers easily adapting views and layouts to suit your ideal SaaS user experience.

Implementing Dynamic Themes

Beyond static style customization, having dynamic themes unlocks changing a SaaS app's look and feel programmatically.

The Next JS SaaS boilerplate implements a theming engine for switching color schemes and styles via context API.

// Example theme provider

export const themes = {
  light: { 
    foreground: "#000",
    background: "#FFF"
  },
  dark: {
    foreground: "#FFF",
    background: "#333"
  }
}

export const ThemeContext = React.createContext(themes.light)

export const ThemeProvider = ({children}) => {
  const [theme, setTheme] = React.useState(themes.light)
  
  return (
    <ThemeContext.Provider value={{theme, setTheme}}>
      {children}
    </ThemeContext.Provider>
  ) 
}

Now any nested component can tap into context to access the active theme and functions for updating it.

This empowers features like theme switchers for toggling modes dynamically based on user preferences.

// Example theme toggle button

export default () => {
  const {theme, setTheme} = React.useContext(ThemeContext)

  return (
    <button 
      onClick={() => setTheme(theme === themes.light ? themes.dark : themes.light)}
    >
      Toggle theme
    </button>
  );
}

In summary, theming support enables building engaging features for customizing a SaaS's look and feel on the fly.

Optimizing Developer Experience (DX) in SaaS Boilerplates

Optimized for rapid development and customization in the SaaS landscape.

Streamlining Code with Linting and Formatting

Achieving consistency with ESLint, Prettier, and EditorConfig in a Next.js environment.

Consistency in code style is critical for developer experience in any Next.js SaaS boilerplate. By leveraging tools like ESLint, Prettier, and EditorConfig, developers can enforce consistent code style guidelines automatically on file save. This streamlines collaboration by eliminating bike-shedding discussions around style.

Here is an example .eslintrc.json file that extends Airbnb's popular JavaScript style guide for linting:

{
  "extends": [
    "airbnb",
    "airbnb/hooks",
    "plugin:jsx-a11y/recommended", 
    "prettier",
    "prettier/react"
  ],
  "plugins": ["prettier"],
  "rules": {
    "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
    "react/react-in-jsx-scope": "off",
    "import/no-unresolved": "off",
    "no-shadow": "off"
  }
}

This integrates Prettier to format code that does not comply with linting rules on file save.

Similarly, adding a .prettierrc config file ensures consistent formatting rules for whitespace, quotes, trailing commas, and more:

{
  "trailingComma": "es5",
  "tabWidth": 2,
  "semi": false,
  "singleQuote": true
}

Finally, applying an .editorconfig standardizes editor configuration across development environments:

root = true

[**]
indent_style = space
indent_size = 2
end_of_line = lf 
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

This combination allows developers to code freely without worrying about style - improving productivity and collaboration in a Next.js SaaS boilerplate.

Handling Environment Variables Efficiently

Best practices for managing configs for development versus production in a SaaS application.

Managing environment variables is critical in any SaaS boilerplate to avoid exposing secrets like API keys in code when deployed.

Next.js has built-in support for environment variables through .env files. For example, .env can store variables available only during development like database URLs:

# .env

DATABASE_URL=postgresql://localhost:5432/dev_db

While .env.production variables are available only when the app is built for production:

# .env.production 

DATABASE_URL=postgresql://user:password@prod-db.com:5432/prod_db

The boilerplate must load variables from the relevant file depending on the environment. This can be achieved cleanly using the next-env module:

// loadEnvConfig.js

import getConfig from "next-env"

const env = getConfig() 

export default {
  databaseURL: env.DATABASE_URL
}

Now databaseURL will contain the value from .env or .env.production automatically.

Other useful libraries include dotenv and dotenv-cli for managing hierarchies of .env files.

Overall, handling environment variables correctly separates development and production config for smooth SaaS boilerplate deployment.

Leveraging Documentation for SaaS Success

Utilizing written guides for customization, deployment, and troubleshooting in the context of a Next.js SaaS boilerplate.

Clear, up-to-date documentation is imperative for developer experience in a Next.js SaaS boilerplate. Well-structured docs empower users to efficiently customize, deploy, and troubleshoot the software.

For example, documentation might cover:

  • Customizing themes/branding
  • Configuring authentication
  • Deploying to production
  • Troubleshooting build errors
  • Integrating with external services
  • Architectural explanations
  • Contributing guidelines

Developers rely heavily on docs to ramp up on unfamiliar software. Excellent documentation directly correlates to user satisfaction.

Useful SaaS documentation strategies include:

  • Task-oriented topics to solve specific user problems
  • Simple quick start guide for initial setup
  • FAQ section for common issues
  • Code snippets to demonstrate functionality
  • Diagrams to explain architecture
  • Versioning docs to match software releases
  • Linked references for deeper explanation
  • Search functionality to easily find information

Popular open source tools for managing technical documentation include MkDocs, GitBook, Docsify, and Docusaurus. These can simplify generating and hosting markup-based documentation.

Overall, comprehensive documentation is a must-have for any functional Next.js SaaS boilerplate.

Concluding Thoughts: Maximizing Your SaaS Platform's Potential

We covered a lot of ground unpacking the core features of Next.js SaaS boilerplates. Now that you have a solid understanding of what these powerful templates offer, you're ready to start building a feature-rich SaaS application faster than ever before.

Recapping the Advantages of Next.js SaaS Boilerplates

Next.js SaaS boilerplates provide immense value through:

  • Speed of development - By handling complex functionality like authentication, databases, API routes, and more out of the box, you save countless hours compared to building from scratch.
  • Feature-richness - With support for multi-tenancy, payments, admin dashboards, and more baked in, you get an enterprise-grade stack without the heavy lifting.
  • Customization possibilities - While packed with features, these boilerplates are designed for extension and customization so you can mold them to your product vision.
  • Optimized DX - Developer experience is top-notch thanks to Next.js, TypeScript, ESLint, Prettier, and other best-in-class tools.

Leveraging these strengths positions your SaaS to delight users and dominate the market.

Exploring Deployment Options for SaaS

With a production-ready SaaS built, next you'll need to deploy it for the world to use. Popular options include:

  • Vercel - Seamless Next.js deployment with serverless functions and globally distributed CDN. Easy path from local development to global scale.
  • Railway - Fully managed infrastructure lets you focus on code while they handle infrastructure, scaling, security, and more behind the scenes.
  • AWS - Flexible but complex, you manage your own servers on industry-leading IaaS. Expert DevOps skills recommended.
  • Heroku - Add-on marketplace for third-party services makes it easy to integrate payment processors, databases, CDNs, and more.

Evaluate these and other platforms based on your team's skills, stage of growth, and requirements.

Further Resources and Community Support

To continue your Next.js SaaS journey:

  • Star the GitHub repo for an example SaaS boilerplate
  • Read the documentation for detailed usage guides
  • Join the Discord community to connect with the builders and users

With these resources plus the knowledge you've gained, you have everything needed to build a world-class SaaS application. Now venture forth and make it a reality!

Related posts

Read more

Built on Unicorn Platform