A city-based event discovery platform built for fast, simple browsing across local events. Next.js, Prisma, and server-side data fetching power the experience, with Framer Motion adding responsive transitions and scroll-linked interactions.
September 2025 · Solo Project · ~1 month, part-time (Aug–Sep 2025), plus a production fix in Oct 2025
Evento is an event discovery platform for browsing events by city. Built with Next.js 15, TypeScript, Prisma, PostgreSQL, Tailwind CSS, and Framer Motion, it uses Server Components and a server-only data-access layer instead of fetching through a separate API route. Event listings are fetched in full and cached on the server, then sliced into pages with a (page - 1) * pageSize offset, while city and pagination parameters are validated before reaching the database.
The goal was to make browsing local events feel fast and focused rather than introduce another application with unnecessary client-side data fetching. The architecture needed to keep database access on the server, avoid an extra API round trip, support pagination as event lists grow, and remain reliable when deployed to a serverless environment.
Frontend
Backend
Solution
Replaced the fetch-based data layer with direct Prisma queries inside Server Components, wrapped in unstable_cache, and marked the DB layer server-only so the client bundle never sees it.
Result
Fewer round trips, smaller client bundle, and no risk of DB credentials leaking into client code.



A Next.js Server Component does not need to call an API route just because it needs data. Keeping the database query in a server-only module can remove an unnecessary network boundary and simplify the application.
Caching belongs close to the data-access layer when the same server-side query can be reused across requests. It keeps caching decisions out of individual UI components.
Serverless deployment changes what is possible at build time. A strategy that depends on a database during local static generation needs to be tested against the actual production build environment.
Pagination should ideally happen at the database query level with LIMIT/OFFSET rather than fetching every row and slicing the array afterward. Evento's current pagination fetches the full cached result set and computes the page slice with a (page - 1) * pageSize offset, which is simple but holds more data in memory than a given page actually needs as the event count grows.
Building city-based [city] and event [slug] routes was a practical lesson in how the App Router's file-system routing, Server Components, and per-segment data fetching fit together — including where static generation stops being an option, as the generateStaticParams issue above showed.
Building Evento strengthened my practical understanding of Next.js Server Components, Prisma, server-side caching, Zod validation, and production deployment on Vercel.