Create a new full-stack TypeScript monorepo (Turborepo + pnpm, AdonisJS 7 API with Tuyau typed client, Next.js 16 web app, shadcn/Base UI package, PostgreSQL) with enforced conventions, generators, git hooks and CI already set up and verified. Use when asked to create, scaffold, bootstrap or start a new project or monorepo with AdonisJS and Next.js, or to reproduce this stack.
Installs into .claude/skills of the current project.
Are you the author of Adonis Next Monorepo?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/nazmulnahid-git-adonis-next-monorepo)
---
name: adonis-next-monorepo
description: Create a new full-stack TypeScript monorepo (Turborepo + pnpm, AdonisJS 7 API with Tuyau typed client, Next.js 16 web app, shadcn/Base UI package, PostgreSQL) with enforced conventions, generators, git hooks and CI already set up and verified. Use when asked to create, scaffold, bootstrap or start a new project or monorepo with AdonisJS and Next.js, or to reproduce this stack.
---
# adonis-next-monorepo
Creates a working monorepo from `template/`, a snapshot of a project whose setup was verified end to end. The result is identical in structure, tooling and configuration; only the name and description change. The template's own `docs/conventions.md` records every convention and why it exists, so read that when the user asks why something is set up the way it is, or wants to change it.
## What it creates
- **Workspaces:** `apps/api` (AdonisJS 7, Lucid/Postgres, VineJS, token + session auth, Tuyau), `apps/web` (Next.js 16 App Router, React 19, Tailwind 4, TanStack Query), `packages/ui` (shadcn on Base UI), `packages/eslint-config`, `packages/typescript-config`.
- **API structure:** feature modules in `app/modules/<name>/<name>.{routes,controller,service,validator}.ts`, generated by `node ace make:module <name>`. Starts with `auth` and `health`. Every response is `{ data }` or `{ errors: [...] }`, and routes require auth unless marked public.
- **Web structure:** `useQuery(api.<module>.<action>.queryOptions())` rendered through `<QueryState>`, plus mutation error toasts and env validated with zod.
- **Tooling:** strict TypeScript 6.0, one ESLint config with custom structure rules, Prettier, Husky + lint-staged + commitlint, branch-name and migration guards, a GitHub Actions CI workflow, Dependabot, VS Code settings, and AI rules in `AGENTS.md`.
## Steps
### 1. Collect the inputs
You need:
- **Name:** kebab-case, e.g. `acme` or `my-app`. It becomes the `@<name>/*` package scope; the Postgres user and databases use the snake_case form.
- **Title:** the display name. Defaults to the name in Title Case.
- **Description:** one line, used in the README and on the home page.
- **Target directory:** must be new or empty.
Ask for any missing input in one message. Then confirm the tools exist: `node -v` (24+), `pnpm -v`, `git --version`, and `docker info` (the Docker daemon must be running; start Docker Desktop if it isn't).
**Done when** all four inputs are known and every tool responds.
### 2. Create the files
```bash
node <this-skill-dir>/scripts/create.mjs <target> --name <name> --title "<Title>" --description "<Description>"
```
Then, inside `<target>`:
```bash
git init -b main # before install: `pnpm install` sets up the git hooks
pnpm install --frozen-lockfile
pnpm format # normalizes the filled-in name and description
```
`--frozen-lockfile` installs exactly the versions the template was verified with. Use that every time; upgrades are a separate, user-approved step (step 6).
**Done when** install exits 0 and `.husky/_` exists.
### 3. Database and environment
```bash
cp apps/api/.env.example apps/api/.env
cp apps/web/.env.example apps/web/.env.local
pnpm --filter @<name>/api exec node ace generate:key
```
Check port 5432 with `lsof -iTCP:5432 -sTCP:LISTEN`. If it's taken (often by another project's Postgres), pick a free port and set it in both `docker-compose.yml` (`'<port>:5432'`) and `DB_PORT` in `apps/api/.env` and `apps/api/.env.example`. Tell the user which port you chose.
```bash
pnpm db:up
pnpm --filter @<name>/api exec node ace migration:run
```
**Done when** the migrations report `Migrated` and `docker compose ps` shows Postgres healthy.
### 4. Verify everything is green
Run from the root, in order: `pnpm format:check`, `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build`.
Then check the generator end to end:
```bash
cd apps/api && node ace make:module smoke_check && cd ../..
pnpm typecheck && pnpm test
```
Remove the smoke module afterwards: delete `apps/api/app/modules/smoke_check/` and `apps/api/tests/functional/smoke_check.spec.ts`, and remove the `smokeCheckRoutes` import and call from `apps/api/start/routes.ts`. Then run `pnpm typecheck` once more.
**Done when** all five commands pass, the smoke module's tests passed, and the tree is back to the scaffold. On any failure, stop and report the command and its output. A fresh scaffold that fails is a template bug: fix the template, not just this copy.
### 5. First commit
Ask the user whether to make the initial commit. If yes:
```bash
git add -A && git commit -m "chore(repo): scaffold <name> monorepo"
```
The commit goes through the hooks (lint-staged, commitlint), which double-checks the scaffold.
**Done when** the commit exists, or the user declined.
### 6. Report and offer next steps
Tell the user what was created and where, the Postgres port, and that `pnpm dev` starts the API on :3333 and the web app on :3000. Then offer these, without doing any of them unasked:
- Fill `CLAUDE.md` and `README.md` with project-specific facts.
- Upgrade dependencies: run `pnpm outdated -r` and show what's behind. Keep TypeScript on 6.0; `@adonisjs/assembler` and typescript-eslint don't support 7 yet. Re-run step 4 after any upgrade.
- On GitHub: push, set `main` as the default branch, and protect it. CI and Dependabot start working once the workflow files are on the default branch.
## Changing the conventions
The scaffolded project is governed by its `AGENTS.md` and `docs/conventions.md`. Change a convention in the project the way those files describe: ask the user, change it, and record it in `docs/conventions.md`. If the change should apply to future projects too, update `template/` in this skill.