Use Cases / Portfolio & Agency Sites

Portfolio & Agency Sites.

Define projects, services, and testimonials as collections and About/Contact as singles. Your client gets a clean admin panel to update content. You keep full control of the data model in your repository.

Key capabilities

  • Collections + Singles — Projects, services, and testimonials as collections. About page and contact info as singles, one document, always there.
  • Media Library — Upload project screenshots, team photos, and client logos. Sharp processing for automatic optimization and responsive sizes.
  • Client Access — Set up editor roles so clients manage content without touching schema, settings, or anything they shouldn't see.
  • Code-first Schema — Define the collection fields in TypeScript. The schema is version-controlled alongside your frontend, no surprises after a client edit.

Client sites need an admin. Building one from scratch is a project in itself.

Your client needs to update their portfolio, add testimonials, and swap out service descriptions without calling you. Building a custom admin is overkill. A hosted CMS adds another monthly subscription and a separate deployment to babysit.

Nextly gives you a full admin panel as part of the Next.js project you're already deploying. No extra service, no extra cost.

Portfolio schema: collections and singles

Projects collection

import {
  defineCollection, text, richText,
  upload, relationship, select,
} from "nextly/config";

export default defineCollection({
  slug: "projects",
  fields: [
    text({ name: "title", required: true }),
    text({ name: "client" }),
    text({ name: "slug", unique: true }),
    richText({ name: "description" }),
    upload({ name: "thumbnail", relationTo: "media" }),
    upload({ name: "gallery", relationTo: "media", hasMany: true }),
    relationship({
      name: "services",
      relationTo: "services",
      hasMany: true,
    }),
    select({
      name: "category",
      options: [
        { label: "Web", value: "web" },
        { label: "Mobile", value: "mobile" },
        { label: "Branding", value: "branding" },
      ],
    }),
  ],
});

Testimonials collection

import {
  defineCollection, text, upload, number,
} from "nextly/config";

export default defineCollection({
  slug: "testimonials",
  fields: [
    text({ name: "quote", required: true }),
    text({ name: "author", required: true }),
    text({ name: "role" }),
    text({ name: "company" }),
    upload({ name: "avatar", relationTo: "media" }),
    number({ name: "rating", min: 1, max: 5 }),
  ],
});

About page (single)

import {
  defineSingle, text, richText, upload,
} from "nextly/config";

export default defineSingle({
  slug: "about",
  fields: [
    text({ name: "headline", required: true }),
    richText({ name: "bio" }),
    upload({ name: "photo", relationTo: "media" }),
    text({ name: "email" }),
  ],
});

Start building with Nextly

Free, open source, and yours to own. No sign-up required.

Terminal