In October the Java stacks were split into layer plugins. Now the TypeScript stack follows: the combined plugin aiup-nestjs-nextjs becomes three layer plugins, aiup-drizzle, aiup-nestjs, and aiup-nextjs. They need aiup-core 3.14.0 or later.
Why split the stack #
aiup-nestjs-nextjs built a NestJS backend with Drizzle and a Next.js frontend with one /implement command. That worked as long as a project used exactly this combination. But many TypeScript projects don't. One is a NestJS REST API without a UI. Another has a Next.js frontend on an existing Spring Boot backend.
With layer plugins, each project takes only the layers it has. And TypeScript projects now work the same way as Java projects: /stack, /use-case-implement, /use-case-test, and /use-case-coverage.
The three plugins #
- aiup-drizzle for the migration and persistence layers:
/drizzle-schemawrites the Drizzle schema from the entity model and generates the PostgreSQL migrations,/drizzle-persistencewrites the repositories, and/drizzle-persistence-testtests them against PostgreSQL in Testcontainers. - aiup-nestjs for the service and API layers:
/nest-serviceimplements the business rules with domain errors,/nest-restwrites the controllers with validated DTOs and Problem Details, and/nest-service-testand/nest-rest-testtest them against a real database. - aiup-nextjs for the UI layer:
/nextjs-uibuilds the App Router pages and components on top of the REST API, and/nextjs-ui-testwrites component tests with Vitest and React Testing Library.
End-to-end tests come from aiup-playwright, as for every other web UI. It now starts the frontend and the API together.
Two rules worth knowing #
Migrations are generated, never written by hand. /drizzle-schema changes the schema file and runs drizzle-kit generate. A hand-written migration would break the journal that Drizzle computes the next migration from. That's why the business rule marker sits in the schema file, not in the SQL.
Next.js is a client of the API. In this stack, Next.js talks to the backend only over HTTP. Server Components and Server Actions also go through the API, never directly to the database. So a project with aiup-nextjs always has an API layer, either /nest-rest or /spring-rest. The contract types are written field by field from that layer's DTOs, and the JSON contract between the two is checked after every implementation.
Combinations #
- REST API with NestJS and Drizzle: aiup-drizzle, aiup-nestjs
- Next.js, NestJS, and Drizzle: aiup-drizzle, aiup-nestjs, aiup-nextjs, aiup-playwright
- Next.js on Spring Boot with JPA: aiup-flyway, aiup-jpa, aiup-spring-boot, aiup-nextjs, aiup-playwright
In all three, a use case is tested once, in the API layer. /stack detects NestJS, Next.js, and Drizzle from package.json and the source tree and records the combination in docs/architecture/stack.md.
Upgrading #
aiup-nestjs-nextjs is deprecated and will be removed with aiup-core 4.0.0, together with aiup-vaadin-jooq and aiup-angular-jpa. Your code, your tests, and everything under docs/ stay as they are. To move a project:
- Uninstall
aiup-nestjs-nextjsand installaiup-core3.14.0 or later withaiup-drizzle,aiup-nestjs,aiup-nextjs, andaiup-playwright. Never keep both forms in one project. - Run
/stackonce to writedocs/architecture/stack.md. - Use
/use-case-implementinstead of/implement, and/use-case-testinstead of the separate test commands. - Your tests keep the use case id in
describe('UC-XXX: …'). Nothing changes there.
Moving an existing project has the details.
Thanks to the contributor who wrote the original aiup-nestjs-nextjs plugin. The new layer skills build on that work. Feedback is very welcome: open an issue in the marketplace repository or get in touch.