A learning project for building a read-only API with:
- Bun
- Next.js App Router
- Elysia
- Eden Treaty for end-to-end type safety
- Prisma ORM v7
- PostgreSQL via Docker Compose
This project demonstrates how to run a Next.js application as the main app while mounting an Elysia server inside a Next.js Route Handler.
The API reads project data from PostgreSQL through Prisma and exposes type-safe access to the frontend through Eden Treaty.
- Runtime / package manager: Bun
- Frontend: Next.js App Router
- API framework: Elysia
- Type-safe client: Eden Treaty
- ORM: Prisma v7
- Database: PostgreSQL
- Local database runtime: Docker Compose
Browser / Next.js Page
↓
Eden Treaty Client
↓
Next.js Route Handler: app/api/[[...slugs]]/route.ts
↓
Elysia App: src/server/app.ts
↓
Project Route: src/server/routes/project.route.ts
↓
Project Service: src/server/services/project.service.ts
↓
Project Repository: src/server/repositories/project.repository.ts
↓
Prisma Client: src/db/prisma.ts
↓
PostgreSQL Docker Containerapp/
├── api/
│ └── [[...slugs]]/
│ └── route.ts
├── projects/
│ ├── [slug]/
│ │ └── page.tsx
│ └── page.tsx
├── layout.tsx
└── page.tsx
src/
├── client/
│ ├── helpers/
│ │ └── api-response.ts
│ └── treaty.ts
├── db/
│ └── prisma.ts
├── generated/
│ └── prisma/
└── server/
├── app.ts
├── domain/
│ └── project.constants.ts
├── repositories/
│ └── project.repository.ts
├── routes/
│ └── project.route.ts
└── services/
└── project.service.ts
prisma/
├── migrations/
├── schema.prisma
└── seed.ts
scripts/
├── test-eden.ts
├── test-elysia-app.ts
├── test-prisma.ts
└── test-project-service.tsCreate a .env file:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/e2e_nextjs_elysia?schema=public"
NEXT_PUBLIC_API_URL="http://localhost:3000/api"docker compose up -dCheck database readiness:
docker exec e2e-nextjs-elysia-postgres pg_isready -U postgresOpen psql:
docker exec -it e2e-nextjs-elysia-postgres psql -U postgres -d e2e_nextjs_elysiaGenerate Prisma Client:
bunx prisma generateRun migration:
bunx prisma migrate devCheck migration status:
bunx prisma migrate statusSeed database:
bun run seedStart Next.js:
bun devOpen:
http://localhost:3000Projects page:
http://localhost:3000/projectsHealth check:
GET /api/healthGet all projects:
GET /api/projectsFilter by status:
GET /api/projects?status=active
GET /api/projects?status=draftFilter by category:
GET /api/projects?category=ai_agent
GET /api/projects?category=backend
GET /api/projects?category=knowledge_baseGet project by slug:
GET /api/projects/:slugExample:
GET /api/projects/ai-agent-workflow-managerProject list:
/projectsFiltered project list:
/projects?status=active
/projects?category=ai_agentProject detail:
/projects/ai-agent-workflow-managerNot found example:
/projects/not-existing-projectTest Prisma connection:
bun scripts/test-prisma.tsTest project service layer:
bun scripts/test-project-service.tsTest Elysia app without Next.js:
bun scripts/test-elysia-app.tsTest Eden Treaty through Next.js API:
bun scripts/test-eden.tsFor test-eden.ts, make sure the Next.js dev server is running:
bun devbun run build- PostgreSQL runs in Docker
- Prisma v7 uses generated client output at
src/generated/prisma - Prisma Client uses
@prisma/adapter-pg - Elysia is mounted inside a Next.js Route Handler
- Eden Treaty client is used by frontend pages
- Project list page supports filters through URL search params
- Project detail page supports dynamic route by slug
- Not found project pages use Next.js
notFound()
This project is intentionally read-only for now.
Not included yet:
- Authentication
- Create/update/delete API
- Pagination
- Search
- Validation error formatting
- Production deployment
- Dockerized Next.js app
These can be added later after the read-only architecture is stable.