Building a Full-Stack Module Registry for NextAPI
Modern full-stack development has become remarkably good at reusing individual pieces of software.
We have package managers for JavaScript and Python. We have component libraries for frontend applications. We have frameworks for APIs, ORMs for databases, authentication libraries, SDKs, UI systems, and countless integrations.
Yet when it comes to building an actual application feature, developers still spend a significant amount of time connecting all of those pieces together.
A package might give you a React component.
Another package might give you a Python library.
Another might provide a database abstraction.
But the application developer still has to create the page, expose the API, configure authentication, create the database structure, add navigation, install dependencies, configure environment variables, and connect everything together.
This raises an interesting question:
What if a complete full-stack feature could be packaged and installed in the same way we install a library?
Not just the frontend.
Not just the backend.
The entire feature.
That is the problem I set out to solve with the NextAPI Module Registry.
The idea behind NextAPI modules
A NextAPI module is a reusable, full-stack application capability.
Instead of thinking about a module as a collection of components or functions, a module can contain everything required to introduce a feature into an application.
A module can provide:
- Frontend pages
- Frontend routes
- Backend routers
- API endpoints
- Database resources
- Functions
- Dependencies
- Environment variables
- Authentication requirements
- Navigation
- Other module dependencies
The important part is that these pieces are not treated as unrelated files.
They are part of one installable unit.
┌─────────────────────────────────────┐
│ NextAPI Module │
├─────────────────────────────────────┤
│ │
│ Frontend │
│ ├── Pages │
│ ├── Routes │
│ └── Navigation │
│ │
│ Backend │
│ ├── Routers │
│ ├── API endpoints │
│ └── Server logic │
│ │
│ Database │
│ └── Module data │
│ │
│ Functions │
│ ├── Provides │
│ └── Uses │
│ │
│ Dependencies │
│ ├── Modules │
│ ├── npm │
│ └── Python │
│ │
│ Configuration │
│ └── Environment variables │
│ │
└─────────────────────────────────────┘
This changes what we mean by reusable software.
A component is reusable.
A library is reusable.
A module is a reusable application capability.
The NextAPI Module Registry
The module system is built around a registry.
The registry provides a central place where modules can be published, discovered, versioned, and consumed by applications.
This is similar to the role package registries already play in software development.
For example, JavaScript developers are familiar with workflows such as:
npm install package-name
The package manager retrieves the package and makes it available to the project.
The NextAPI workflow is conceptually similar:
nextapi add profile-page
The difference is what is being installed.
Instead of installing a library that the developer then has to integrate, the developer is adding a complete application capability.
After adding modules, the application can be synchronized:
nextapi sync
The synchronization process resolves the modules required by the application and integrates them into the NextAPI project.
This creates a registry specifically designed around full-stack application composition.
Why not just use npm?
This is an important distinction.
NextAPI modules are not intended to replace npm packages.
npm solves a different problem.
A JavaScript package might provide:
React component
Utility function
SDK
State management library
UI library
A Python package might provide:
Database client
Authentication library
AI SDK
Utility library
These are useful building blocks, but they do not necessarily know anything about the structure of the application consuming them.
A NextAPI module operates at a higher level.
For example, an AI module could contain:
AI Module
│
├── Frontend
│ └── /ai
│
├── Backend
│ └── /api/ai
│
├── Database
│ └── conversations
│
├── Functions
│ ├── send_message
│ └── create_conversation
│
├── Dependencies
│ ├── npm packages
│ └── Python packages
│
└── Environment
└── AI_API_KEY
The developer is not simply installing an AI library.
They are installing an AI feature.
The distinction is the foundation of the module architecture.
What is a NextAPI module?
A module is essentially a self-contained unit that describes both its implementation and how that implementation integrates with a NextAPI application.
A simplified module structure could look like:
my-module/
│
├── module.json
│
├── frontend/
│ ├── pages/
│ └── components/
│
├── backend/
│ ├── router.py
│ └── ...
│
└── ...
The most important file is the module manifest:
module.json
The manifest acts as the contract between the module and the NextAPI runtime.
It tells NextAPI what the module provides, what it requires, and how it should be integrated.
A module manifest can describe things such as:
Module identity
│
├── Name
├── Version
└── Namespace
│
▼
Compatibility
│
└── NextAPI version
│
▼
Dependencies
│
├── Modules
├── npm
└── Python
│
▼
Application integration
│
├── Frontend
├── Backend
├── Database
└── Functions
│
▼
Configuration
│
└── Environment variables
This machine-readable description is what allows the CLI and registry to understand a module without requiring every integration step to be manually implemented by the application developer.
Frontend integration
One of the major differences between a conventional package and a NextAPI module is that a module can contribute directly to the application's frontend.
A module can declare the routes it provides.
For example:
{
"frontend": {
"routes": [
{
"path": "/profile",
"protected": true,
"label": "Profile"
}
]
}
}
The module is effectively saying:
I provide a profile feature, and that feature has a
/profileroute.
The application does not need to independently know how that feature should be represented.
The module declares the information required by the application.
This also makes the module system useful for application navigation.
A module can describe the route and associated navigation information, allowing the application shell to incorporate the feature when the module is installed.
Instead of manually modifying several unrelated parts of the application, the feature travels with its integration metadata.
Backend integration
A full-stack feature also needs a backend.
NextAPI modules can provide backend functionality through FastAPI routers.
For example:
{
"backend": {
"router": {
"module": "backend/router.py",
"attr": "router",
"prefix": "/profile"
}
}
}
The module contains the backend implementation.
For example:
from fastapi import APIRouter
router = APIRouter()
@router.get("/")
async def get_profile():
...
NextAPI can then integrate that router into the application's backend.
The module therefore has a clear boundary:
NextAPI Application
│
├── Core backend
│
└── Installed modules
│
├── Profile router
├── AI router
├── Analytics router
└── Billing router
Each module can contribute backend functionality without requiring the entire application backend to be manually rewritten around it.
Database integration
Frontend and backend code are only part of a full-stack feature.
Many features require persistent data.
This is where the module architecture goes beyond a conventional component or library system.
A module can declare its database requirements and maintain data belonging to that module.
For example:
Analytics Module
│
└── Analytics data
Notifications Module
│
└── Notification data
AI Module
│
└── Conversation data
The module boundary therefore extends into the data layer.
This matters because a module should ideally be capable of being developed and maintained independently.
If a developer installs an analytics module, they should not have to manually construct the database structure that the module requires.
The module should describe what it needs.
The framework can then integrate those requirements into the application.
Functions and capabilities
One of the more interesting parts of the architecture is the function system.
Modules can expose functions and consume functions provided by other modules.
For example, a module could declare:
{
"functions": {
"uses": [
"auth.get_current_user",
"profile.get_display_name"
]
}
}
Another module can provide those capabilities.
This creates a capability-oriented relationship between modules.
Instead of thinking:
Module A imports internal code from Module B
the relationship becomes:
Module A
│
│ requires
▼
profile.get_display_name
▲
│ provides
│
Module B
This is useful because the consumer does not necessarily need to know how the provider implements the function.
It only needs the capability.
That creates the possibility of building modules that communicate through stable contracts rather than tightly coupling themselves to each other's internal source code.
Module dependencies
Modules can also depend on other modules.
Imagine an AI workspace that requires a user profile system.
The AI module can declare that dependency:
{
"requires": {
"modules": [
"profile-page@^1.0.0"
]
}
}
The developer can then install the AI workspace without manually determining every dependency it requires.
The dependency graph might look like:
AI Workspace
│
├── Profile
│ │
│ └── Authentication
│
└── AI Provider
The module system can resolve this graph when synchronizing the application.
This becomes increasingly important as the ecosystem grows.
A module can build on another module without forcing every application developer to understand the entire dependency tree.
npm and Python dependencies
NextAPI modules can also declare dependencies from the underlying ecosystems.
For example, a frontend module may require an npm package:
{
"dependencies": {
"frontend": {
"npm": {
"react-markdown": "^9.0.0"
}
}
}
}
A backend module may require a Python package:
{
"dependencies": {
"backend": {
"pypi": {
"anthropic": "^0.40.0"
}
}
}
}
This creates a dependency hierarchy:
Application
│
▼
NextAPI Module
│
├── Module dependencies
│
├── npm dependencies
│
└── Python dependencies
The module therefore sits above the existing package ecosystems rather than attempting to replace them.
Environment variables
Application capabilities frequently require configuration.
An AI module might require an API key.
A payments module might require merchant credentials.
An email module might require SMTP configuration.
These requirements can be described by the module.
For example:
{
"env": {
"backend": [
{
"key": "AI_API_KEY",
"required": true,
"secret": true
}
]
}
}
The module now declares an important part of its runtime requirements.
This is another example of why a module is more than a package.
The module is describing the complete environment required by a feature.
Namespaces and isolation
Once you have a public registry, naming becomes important.
Different developers may want to create modules with similar names.
A registry needs a way to distinguish them.
NextAPI supports scoped modules:
@alice/profile
@bob/profile
This allows independent developers to publish modules without competing for the same global name.
Namespaces are also important inside the application.
A module should not accidentally overwrite another module's routes, backend code, or database resources.
The module architecture therefore provides isolation around module-specific resources.
Conceptually:
@alice/profile
│
├── Routes
├── Backend
└── Database
@bob/profile
│
├── Routes
├── Backend
└── Database
Both modules can exist in the same ecosystem without requiring their internal implementation details to collide.
Versioning
A registry is only useful if developers can depend on modules reliably.
That makes versioning a core part of the system.
A module can specify its version:
profile-page@1.2.0
Applications can then specify compatible version ranges:
profile-page@^1.2.0
A module can also define the versions of NextAPI it supports.
For example:
NextAPI >=1.0.0 <2.0.0
This allows the registry and CLI to reason about compatibility instead of simply installing whatever happens to be available.
Published versions should also be immutable.
If version 1.2.0 changes after an application has already consumed it, reproducibility becomes difficult.
A change should therefore result in a new version.
This gives modules predictable version semantics similar to the package ecosystems developers already understand.
The module lifecycle
From the outside, installing a module is simple.
nextapi add profile-page
Then:
nextapi sync
Internally, there is much more happening.
A simplified view of the lifecycle looks like this:
nextapi add
│
▼
Stage the module
│
▼
Resolve dependencies
│
▼
Validate compatibility
│
▼
Fetch module
│
▼
nextapi sync
│
▼
Integrate frontend
│
▼
Integrate backend
│
▼
Integrate database
│
▼
Register functions
│
▼
Resolve configuration
│
▼
Application
This is the important architectural difference.
The CLI is not merely copying files.
It is interpreting the module definition and using it to modify the application in a predictable way.
Drift detection
Once modules become part of an application, another problem appears.
What happens if a developer manually changes something that originally came from a module?
This creates what can be thought of as application drift.
The module system therefore needs to know what it installed and what the current state of the application looks like.
That makes synchronization more than an installation command.
It becomes a mechanism for maintaining the relationship between:
Registry
│
▼
Module definition
│
▼
Installed application
If the application changes outside the expected module structure, the system can identify that state rather than blindly overwriting it.
This is important if modules are going to become a long-term part of application development rather than a one-time code generator.
Building and publishing your own modules
The registry is not limited to modules created by the NextAPI team.
The entire point of the registry is to give developers a way to build their own full-stack capabilities and distribute them.
If you build a module for an internal business system, you can keep it private.
If you build something that could be useful to other developers, you can publish it publicly.
This gives the registry two important use cases:
NextAPI Registry
│
┌────────────┴────────────┐
│ │
Public Private
│ │
Community modules Internal modules
│ │
Wider distribution Controlled distribution
Building your own module
A module does not have to be created by NextAPI itself.
A developer can create a module using the NextAPI module structure and define the parts of the application it provides.
For example, imagine building a task management module.
task-manager/
├── module.json
├── frontend/
│ ├── pages/
│ ├── components/
│ └── ...
├── backend/
│ ├── router.py
│ ├── services/
│ └── ...
└── ...
The manifest describes how those pieces integrate with NextAPI.
The module might expose:
Frontend
└── /tasks
Backend
├── GET /tasks
├── POST /tasks
├── PUT /tasks/{id}
└── DELETE /tasks/{id}
Database
└── tasks
Functions
├── create_task
├── update_task
└── assign_task
Once the module is complete, it can be published to the registry.
This is where the registry becomes more than a collection of official features.
It becomes a platform for developers to distribute their own application capabilities.
Public modules
A public module can become part of the wider NextAPI ecosystem.
For example, a developer might build:
@developer/stripe-billing
@developer/ai-chat
@developer/analytics
@developer/notifications
Other developers can discover those modules and install them into their own applications.
The module author does not need to maintain a separate integration process for every application.
The module itself contains the integration definition.
The registry handles distribution.
That creates a feedback loop:
Developer
│
▼
Build module
│
▼
Publish
│
▼
Community discovers module
│
▼
Developers install it
│
▼
More applications use it
│
▼
Module evolves
This is the beginning of an ecosystem rather than simply a framework feature.
Private modules
Not every module should be public.
Companies often build functionality specifically for their own products and internal systems.
A business might have a module for:
Internal CRM
Employee management
Company reporting
Internal billing
Warehouse management
Customer workflows
Those modules may contain proprietary business logic and should not be available to the public.
The same module architecture can therefore be used for private application capabilities.
Company
│
├── Core application
│
├── Private CRM module
├── Private billing module
└── Private analytics module
This gives organizations a way to build their own internal module ecosystem without exposing proprietary functionality.
Sharing modules
A module can also be shared deliberately rather than simply being published as a public community package.
This creates another useful model for teams.
Imagine a company with several applications:
Company
│
├── Customer Portal
├── Admin Platform
├── Mobile Application
└── Internal Dashboard
Instead of implementing the same feature independently in each application, the company can maintain a shared module.
Shared Module
│
┌──────────────┼──────────────┐
│ │ │
Customer Portal Admin App Mobile App
When the shared module evolves, applications can consume compatible versions of it.
This is one of the reasons versioning and dependency management are fundamental parts of the registry.
The community becomes the extension layer
The most interesting possibility is what happens when module creation is opened to the community.
The NextAPI team does not need to build every possible application capability.
Developers can build modules for the problems they understand best.
One developer might build an invoicing system.
Another might build an AI agent framework.
Another might build a booking system.
Another might build a dashboard.
Another might build an ecommerce feature.
Another might build an internal enterprise workflow.
Each becomes a potential module in the ecosystem.
The registry then becomes a place where developers can discover capabilities rather than simply searching for libraries.
NextAPI Registry
│
┌───────────────┼───────────────┐
│ │ │
Billing AI Chat Analytics
│ │ │
Teams CRM Notifications
│ │ │
└───────────────┼───────────────┘
│
Your Application
The goal is not to dictate what developers build.
It is to give them a standard way to package and distribute what they build.
The registry as an ecosystem
Package registries gave developers a marketplace for reusable code.
Component registries gave developers a marketplace for reusable UI.
A full-stack module registry can provide a marketplace for reusable application capabilities.
The difference is the level of abstraction.
Instead of searching for:
"React calendar component"
a developer could eventually search for:
"Booking system"
and find a module that provides:
Booking Module
├── Calendar UI
├── Booking pages
├── Booking API
├── Database
├── Availability logic
├── Authentication
└── Functions
The developer is no longer looking for the individual pieces required to build the feature.
They are looking for the capability itself.
NextAPI Core and the Registry
The registry is only one part of the architecture.
NextAPI Core provides the application foundation that modules integrate with.
The core provides the runtime and common infrastructure required by the application, including the Next.js frontend, FastAPI backend, authentication, authorization, database support, Docker configuration, and mobile application support.
The registry provides the extensibility layer.
Registry
│
┌───────────────┼───────────────┐
│ │ │
Profile AI Chat Analytics
Module Module Module
│ │ │
└───────────────┼───────────────┘
│
NextAPI Core
│
┌──────────┴──────────┐
│ │
Next.js FastAPI
│ │
└──────────┬──────────┘
│
Database
This separation is intentional.
The core should provide the foundation.
The ecosystem should provide the features.
If every feature had to be included directly inside the core, the core would eventually become a massive collection of unrelated functionality.
The registry allows the platform to remain focused while the ecosystem grows independently.
From components to capabilities
This is the larger idea behind the project.
Frontend development has spent years moving toward composability.
We moved from writing everything manually to reusable functions.
Then libraries.
Then components.
Then design systems.
The same principle can be applied to full-stack application features.
Consider a profile component:
<ProfileCard />
That is reusable UI.
A profile module can instead provide:
Profile Module
│
├── Profile page
├── Frontend components
├── Backend API
├── Database storage
├── Authentication
├── Navigation
└── Functions
The component is a building block.
The module is a capability.
That is a much larger unit of reuse.
Building an application from modules
Once the module becomes the unit of reuse, the application development workflow changes.
Instead of starting with a large empty repository and manually assembling every subsystem, an application can start with the NextAPI foundation and add capabilities as required.
For example:
NextAPI Core
│
├── Authentication
│
├── Teams
│
├── Billing
│
├── AI Agent
│
├── Analytics
│
├── Notifications
│
└── Custom Modules
The resulting application is still a normal full-stack application.
The difference is how its capabilities are assembled.
A developer can choose the capabilities required by the product instead of beginning with every feature already bundled into the application.
This also means that two applications can share the same core while having completely different capabilities.
NextAPI Core
│
┌───────────┴───────────┐
│ │
App A App B
│ │
┌────┼────┐ ┌────┼────┐
│ │ │ │ │ │
Auth CRM AI Auth Billing Chat
The core remains consistent.
The application becomes composable.
AI as a consumer of the registry
AI is another interesting consequence of this architecture, although it is not the reason for the registry.
AI coding agents are becoming increasingly capable of modifying applications.
But asking an agent to integrate a complex feature still means asking it to understand a large amount of application-specific code.
A structured module registry provides another possibility.
Instead of asking an agent to build every subsystem from scratch, the agent could eventually reason about available modules and their capabilities.
A request such as:
Add authentication, team management, billing, and an AI chat system.
could become a problem of finding compatible capabilities in the registry.
The module manifest provides structured information about:
Capabilities
Dependencies
Compatibility
Frontend
Backend
Database
Functions
Configuration
That gives software agents a much more structured surface to work with than an arbitrary collection of repositories.
AI therefore becomes one potential consumer of the registry.
The registry itself remains useful without AI.
The application as a dependency graph
There is another way to think about this architecture.
A traditional application is often represented as a collection of source files:
Application
├── frontend
├── backend
├── database
├── components
├── services
└── configuration
A module-based application can additionally be viewed as a dependency graph:
Application
│
┌──────────┼──────────┐
│ │ │
Profile Billing AI
│ │ │
│ │ ├── AI Provider
│ │ │
└────┬─────┘ │
│ │
Authentication ───────┘
Each module becomes a node in that graph.
Each dependency becomes an edge.
Each function requirement becomes a capability relationship.
This gives the application a structure that can be reasoned about programmatically.
The registry is therefore not simply a website containing downloadable modules.
It is the source of a dependency ecosystem for full-stack applications.
Why the registry matters
The registry is what makes the module model scalable.
Without a registry, modules would simply become another form of local code organization.
With a registry, modules can become distributed software.
They can have:
- Authors
- Namespaces
- Versions
- Dependencies
- Compatibility requirements
- Publishing workflows
- Discovery
- Installation
- Updates
- Public or private distribution
That creates the possibility of an ecosystem rather than just a framework feature.
The long-term idea is straightforward:
Build a capability once, package the complete integration, publish it, and make it available to other applications.
Where NextAPI is going
NextAPI started from a relatively simple question:
How can we make building full-stack applications easier?
The answer turned out to be less about adding more features to a starter project and more about changing the unit at which applications are assembled.
Instead of treating the application as a collection of manually connected pieces, NextAPI treats it as a platform that can be extended through modules.
Those modules can contain frontend code.
They can contain backend code.
They can define database requirements.
They can provide and consume functions.
They can depend on other modules.
They can declare their environment requirements.
They can be versioned and distributed through a registry.
That is what makes the idea different from another component library or another full-stack boilerplate.
The objective is to make application capabilities composable.
The NextAPI Core repository is available on GitHub, and the module registry and documentation are available at nextapi.app.
The interesting part is not any single module.
It is what happens when developers can build, publish, discover, share, and install thousands of them.
That is the direction I am exploring with NextAPI.

Top comments (0)