A hands-on method for evaluating a Next.js SaaS boilerplate: build one realistic feature and examine its architecture, authorization, data access, migrations, and tests.
A demo proves that a starter runs. One small end-to-end feature shows what it actually takes to extend it.
A Next.js SaaS boilerplate can look finished before you have written any product code. Sign-up works, the dashboard loads, and billing is connected. The README explains how to run the app. The demo looks more like a product than a blank repository.
Those are good signs, but they answer only one question: can you run the starter? They tell you much less about what it will be like to add the feature your product actually needs.
Feature lists are a poor proxy for that. Two starters may both include authentication, billing, teams, email, and an admin area, yet feel very different to extend. One may have clear conventions that guide new work. Another may contain several working examples that do not quite fit together.
Before choosing a Next.js SaaS boilerplate, add one small feature that is not already in the demo. Pick something that touches the UI, server-side logic, persistence, authorization, validation, and tests. It does not need to be impressive. It needs to show how the pieces fit together—and where you are left guessing.
Choose something small enough to implement without turning the evaluation into a side project, but substantial enough to cross the boundaries your application will use.
For a B2B product, you might add saved reports to a workspace. A member can create a report with a name and a set of filters, see it in a list, rename it, and delete it. The reports belong to a workspace, so one customer must never be able to read another customer's data.
Make the permission model explicit before you start. For this example, suppose all workspace members can view reports, while only the creator or a workspace admin can rename or delete one. A different product may need different rules; what matters is that the test has an unambiguous expected behavior.
A feature this ordinary still raises the questions that matter in real SaaS work:
Choose something else if saved reports are too similar to a feature the starter already includes. Pick a small piece of real product work that forces the repository's conventions to work together.
Don't start with a vague instruction like “build saved reports” and judge the result afterward. Whether you write the code yourself or use an AI coding agent, important decisions can otherwise stay implicit: who is allowed to do what, how failures should work, and where the logic belongs.
Write down the expected behavior first. For the saved-reports example, the criteria might be:
This is not a full product specification. It is enough to make the test repeatable. Use the same criteria—and the same prompt—when comparing repositories.
Before coding, inspect one or two similar features in the repository. If you are using an agent, ask it to identify the patterns it plans to follow, the files likely to change, and any unresolved questions. Treat its explanation as a hypothesis, not proof; check the code and the eventual diff.
A feature can look fine in the browser and still violate the architecture or permissions you meant to test. Pay attention to how the change fits into the codebase, not just how the final screen looks.
Not every concern needs its own abstraction. The common path should, however, be easy to find. When adding a workspace feature, you should be able to find how similar features handle routing, data access, validation, and server-side operations.
See whether the implementation follows those patterns or introduces a parallel way to solve the same problem. A new helper may be justified; another inconsistent implementation may mean the conventions are unclear. Review the diff and surrounding code, not just a summary of what changed.
Multi-tenant behavior is a useful test because the UI is only one part of the security boundary. Hiding a Delete button from the wrong user does not protect an operation if the server accepts an arbitrary record ID.
Trace the request to the data-access layer. Find where the current user and workspace are established, then verify that the operation checks workspace membership and the permission required for that report. Then inspect the negative tests. A test showing only that an allowed request succeeds leaves a central part of the requirement unproven.
Adding a table or field should not depend on unexplained manual steps. Look at how the project defines its schema, creates and applies migrations, and prepares data for local development and tests. Where relevant, check whether a clean environment can be set up using documented commands. If there is no clear path, it may be difficult to keep development, test, and production databases aligned.
The happy path is usually the easiest part to get working. What happens when a report has no name, the database operation fails, the workspace no longer exists, or the session expires? The interface does not need elaborate custom treatment for every case, but its behavior should be deliberate and consistent with the rest of the application.
A passing build is necessary, but it does not prove the feature is safe or correct. Look for tests that express the contract: a member can read allowed data, a different workspace cannot, unauthorized changes are rejected, invalid input fails, and an unsuccessful operation is not presented as successful. Tests should make important rules understandable to the next developer, not merely satisfy a coverage threshold.
After implementing the feature, record what happened. Which project-specific decisions did you have to guess? Did you find a documented pattern or infer one from unrelated files? Was existing validation and authorization code reused? How often did you have to correct the same mistake? Could you run the relevant tests using the documented setup, or did you need to discover extra services and undocumented steps?
Do not score the starter by the raw number of changed files. A sound vertical slice may touch a schema, a server-side operation, a page, and several tests. A short diff can still be wrong if it bypasses the permission model. A larger diff can be reasonable if it follows the project's established layers.
For each candidate, note which conventions were clear, where you had to guess, what the tests covered or missed, and how much setup work was needed. Run the same exercise on every starter you're seriously considering. You won't get a universal ranking, but you will have evidence tied to the work you expect to do.
This matters whether you write the code yourself or use an AI coding agent. A repository should make it possible to see where business logic belongs, how authentication and workspace access are enforced, how migrations run, and which patterns new work is expected to follow.
I ran into the problem while adding promo-code support and extending referrals in my own product. An AI coding agent would sometimes duplicate logic that already existed, put a module in the wrong part of the codebase, or add imports that went against the intended dependency hierarchy. I would fix the structure and refactor the code, then a later session would bring some of the same problems back. The frustrating part wasn't one bad change; it was having to do the same cleanup again.
I realized that instructions and examples were only part of the answer. Some rules about module boundaries and import direction were implicit, and nothing checked them consistently. That experience pushed me toward making important architecture rules explicit and verifiable, rather than relying on each new session to preserve them.
Clear instructions and consistent examples still matter. Tests matter too, but ordinary feature tests may not catch an import that violates the intended dependency direction or a module placed in the wrong layer. When evaluating a starter, look for conventions that are easy to discover and, where it matters, checks that can flag these violations before they accumulate. A long AGENTS.md file cannot compensate for inconsistent code.
Run the experiment in a disposable branch. You are evaluating how a change fits into the project, not adding experimental code to the product you intend to ship. Keep the prompt and acceptance criteria so you can repeat the exercise on another starter—or after an update.
There are limits to this exercise. A starter cannot know your domain, and no set of conventions replaces engineering judgment. Some projects make stronger decisions about authentication, data access, hosting, or UI because coherent defaults are more useful than an abstraction for every possible choice.
That can be a good trade-off. The goal is not to make every dependency interchangeable or hide every implementation detail behind another layer. It is to understand how the starter expects new work to fit into the system—and whether those expectations suit the product you plan to build.
If the starter already implements a feature you need, inspect that implementation instead of rebuilding it just to complete the exercise. If your chosen feature falls outside the starter's intended scope, that is useful information too. Evaluate a boilerplate against the work you are likely to do, not an imaginary product that needs everything.
I build Codapult, a Next.js SaaS boilerplate and starter kit for MVPs, team-based B2B products, and AI-powered applications. I have a commercial interest in this space, so treat Codapult as one candidate to evaluate—not as an independent verdict. Apply the same test to it and to any other starter: choose a realistic feature, trace the boundaries, and see whether the code gives you a clear path forward.
A feature list tells you what a starter claims to include. A small, realistic change gives you a better sense of what working in that codebase will be like. Try the kind of change you expect to make next before committing to it.
Choose a Next.js SaaS boilerplate you can understand, adapt, and own.
Codapult is a Next.js SaaS Boilerplate & Starter Kit for MVPs, team-based B2B products, and AI-powered applications, featuring connected product workflows, modular architecture, a built-in AI platform, billing, and infrastructure. Before choosing a starter, examine how authentication, payments, and data access fit together—and choose an architecture that can evolve with your product rather than locking you into its original assumptions.