A maintainable Next.js SaaS architecture makes it easy to answer three questions: where does a business rule live, which code may access customer data, and what must change when a workflow grows? Start with those boundaries before deciding how many folders, packages or services to create.

For a small B2B product, one application and one primary database can be a useful starting point. The important decision is to keep domain behavior understandable within that application. Adding another deployment does not automatically give a team clearer ownership.

Organize around the product's work

Consider a hypothetical supplier review application. Customers create review projects, collect evidence, invite colleagues and approve suppliers. Those are meaningful product areas. They should remain visible in the code alongside supporting concerns such as authentication, billing and email.

Next.js defines route and file conventions, while allowing different organizational approaches through folders and route groups. Its project structure guide is a reference for framework behavior. Your domain boundaries still require an explicit design.

Keep route files focused on receiving input and presenting output. A supplier approval operation belongs in a domain module that can also serve a background task or API endpoint. Avoid placing the actual approval rules inside a button component simply because that is where the feature first appeared.

Give data access a clear boundary

A database query should happen with enough context to determine who is asking, which workspace they are acting in and which operation they may perform. Passing only a supplier ID through the application makes those assumptions difficult to inspect.

For new projects, Next.js recommends a server-only data access layer that performs authorization and returns minimal data objects in its data security guidance. A practical implementation exposes business-focused operations such as finding reviewable suppliers for a workspace, rather than sharing unrestricted database access everywhere.

The returned data should suit the screen or operation. A review page may need supplier name, status and reviewer notes. It does not need provider credentials, internal billing identifiers or unrelated private fields. Narrow results make accidental exposure harder and future changes easier to assess.

Separate reading from changing state

Reading a list and approving a supplier have different responsibilities. The list needs filtering, pagination and an appropriate empty state. Approval needs authorization, validation of the current state and an intentional record of the change.

Make mutations small enough to explain. An approval operation might confirm workspace membership, check approval permission, verify that required evidence exists, update the review and record an event. If notification delivery fails afterward, that should not silently reverse a completed approval.

Decide which changes must succeed together. Updating the approval and recording the event may belong in one database transaction. Sending email is an external side effect with its own failure behavior. Writing these boundaries down is more useful than relying on the happy path implied by a screen.

Follow one workflow through the architecture

Imagine a reviewer exports an approved supplier report. The screen submits a report request. Server logic validates the request, resolves the workspace and checks permission. A domain operation verifies that the review is exportable and records an export job. A worker produces the file, and an authorized download operation later returns access to it.

Each step has a clear owner:

ResponsibilitySuggested homeKey question
Receive the export requestRoute handler or server actionIs the input valid and which authenticated workspace is acting?
Authorize the operationServer-side application or domain policyMay this member export this workspace’s review?
Validate review state and create a jobDomain operation and database transactionIs the review exportable, and is the job durably recorded?
Read the scoped report dataServer-only data access layerDoes each record belong to the authorized workspace?
Generate the fileBackground workerCan processing recover safely after interruption?
Return download accessAuthorized server endpointDoes the requester still have access to the completed file?