Back to Work

A Designer-Operated Portfolio With No Developer in the Loop

Designer-Operated PortfolioMarketing / Portfolio Site

A headless Next.js marketing and portfolio site for an interior design studio, backed by a Sanity-managed schema covering projects, artwork, journal posts, and curated product picks. Built with App Router, ISR, and a self-serve Studio so the designer can publish without a developer. The studio needed a portfolio site they could update themselves: new projects, new artwork, new product picks, all without filing a ticket. Off-the-shelf builders couldn't model the relationships between a project and the products specified inside it, and a custom CMS would have left the studio dependent on us forever. The brief was a designer-operated site that still rendered like a hand-built one.

Industry

Interior design and fine art

Independent interior design studio

Independent design practices need editorial-quality portfolios that double as a sourcing record, not the templated grid-of-thumbnails that every Squarespace site collapses into.

Existing studio rebuilding their web presence to pair finished-project storytelling with an ongoing journal and a curated picks section that drives the studio's point of view.

A Portfolio That Edits Itself

Four content types, one editorial voice

Portfolio projects, artwork, journal posts, and picks each have their own shape, but every page links across them. Modeling that without forcing the studio to duplicate content was the central schema problem.

Mixed media in the hero slot

Some projects open on a still photograph, others on a silent looping video. The schema had to enforce that exactly one of the two was provided, plus a static grid thumbnail when video was used so listings stay quiet.

Project and product crosslinks

A finished interior should surface the actual chairs, lights, and finishes used. That meant a referenced relationship between portfolio and picks, queryable in both directions, without making the editor rebuild the list each time.

Designer-friendly Studio

The client publishes their own content. Validation, conditional fields, and grid-layout previews had to do the work that a developer review otherwise would.

No stale pages, no rebuild storms

New picks and journal posts go up frequently. The site needed to refresh quickly without redeploying on every edit.

User-First, AI-Native Development

Discovery & Research

  • Audited the studio's existing site to map which content types actually drove traffic and which were vestigial
  • Walked through the editor's publishing workflow to identify where a CMS would help versus where it would just add ceremony
  • Reviewed reference portfolios in the interior-design space to calibrate density, motion, and gallery behavior

Architecture Design

  • Next.js 16 App Router with React 19 server components for every public route, client components reserved for genuinely interactive surfaces (lightbox, search modal, header dropdown)
  • Sanity CMS as the single source of truth, queried via GROQ through next-sanity
  • Studio mounted at /studio inside the same Next.js app so the editor never leaves the site to publish
  • Resend for the contact form, kept as a thin server action with field validation
  • ISR with a 60-second revalidate window so edits go live without a redeploy

Core Technical Decisions

1. Sanity over a database-backed CMS

The content shape is editorial, not transactional. Sanity's schema-as-code meant the project, picks, and journal models live in version control next to the components that render them, and Studio is generated from those schemas. We rejected a generic headless DB because there was no need for write paths beyond the contact form.

2. Server components by default

Every listing and detail page fetches GROQ in a server component and passes typed data to a client wrapper only where motion or modal state is needed. This keeps the JS bundle small and image URLs signed server-side via @sanity/image-url.

3. Conditional schema fields with custom validation

The portfolio schema branches on heroMediaType. When a project is video, the featured image hides and a gridThumbnailImage becomes required so listing pages never render a video tag in a grid cell. The validation runs in Studio, not at render time, so the editor catches mistakes before publish.

4. Referenced picks instead of embedded ones

portfolio.relatedPicks is an array of references that dereferences in the detail query. One pick can appear on many projects without being duplicated, and updating a product link updates it everywhere.

5. Orderable documents for editorial control

The studio wanted to hand-order projects, not sort by date. Adding orderable ranks via @sanity/orderable-document-list to portfolio, artwork, journal, and picks gave them drag-and-drop ordering in Studio that the GROQ queries respect via order(orderRank).

6. ISR over on-demand revalidation

A 60-second revalidate window was the right tradeoff for a site that publishes a few times a week. Webhook-driven revalidation would have been more code for a benefit the editor would never feel.

Iterative Development Phases

  1. 1.Stand up the four schemas and query them through GROQ before any styling
  2. 2.Wire Studio at /studio and validate the editor flow end to end
  3. 3.Build portfolio listing and detail with image hero only
  4. 4.Layer in video hero support, grid thumbnails, and lightbox
  5. 5.Add picks, journal, artwork, and the cross-references between them
  6. 6.Contact form, navigation visibility controls, homepage composition

Key Features Delivered

Portfolio system with mixed media heroes

  • Image or video hero per project, enforced at the schema level
  • Required grid thumbnail when hero is video, so listings stay static
  • Hotspot-aware images for sane cropping at every breakpoint

Product picks linked to projects

  • Dedicated picks content type with image, excerpt, external link, and seller
  • relatedPicks references on portfolio projects, dereferenced in the detail query
  • ProjectPicksSection and PicksByProjectGallery surface picks both ways

Editor-controlled navigation and homepage

  • Per-menu-item visibility toggles in navigationSettings so sections can be hidden without code changes
  • Homepage settings document drives featured portfolio, artwork, journal, and picks blocks

Image lightbox with thumbnail strip

  • Full-screen gallery with keyboard navigation and a thumbnail rail for orientation in long galleries

Journal with categories and rich text

  • Portable Text rendering through @portabletext/react for inline images, links, and structured content

Contact form with server-side delivery

  • Resend integration behind a validated API route; sender address and recipient pulled from env, no secrets in client code

Studio at /studio with @sanity/vision

  • Editor and developer share one URL: the client publishes; we debug GROQ in the same surface

Technical Highlights

Frontend

Next.js 16 (App Router), React 19, TypeScript 5, Tailwind CSS 4

Backend

Next.js server components and route handlers, ISR with 60s revalidate

APIs & Integration

Sanity CMS 4 (next-sanity, @sanity/image-url, @sanity/vision, @sanity/orderable-document-list), Resend for transactional email, Portable Text via @portabletext/react

DevOps

Vercel-class hosting, GitHub-managed schema-as-code

Production-Ready Success

Shipped a production site spanning portfolio, artwork, journal, picks, about, and contact, all driven by Sanity

Editor publishes new projects, posts, and picks without a developer in the loop, with Studio validation catching missing alt text, missing video thumbnails, and broken hero configurations before publish

Cross-linked picks and projects in a single GROQ round trip, so a project page renders its sourced products with no follow-up fetches

Navigation and homepage composition fully editor-controlled, including per-item visibility, so sections can be hidden during seasonal pushes without a deploy

Server-rendered detail pages with hotspot-aware Sanity image URLs, keeping the public bundle to interactive surfaces only

ISR with a 60-second window means edits propagate quickly without rebuild churn

Need a Site Your Editors Can Actually Run?

If you're shipping editorial work and tired of filing tickets to update your own pages, a headless build with a tightly modeled Studio gets you out of that loop. We design schemas that prevent broken publishes, queries that render in one round trip, and Studios that feel like the editor's tool, not the developer's.