CoursesHandling schema changes confidentlyTidy up the schema and front end code
Certification
Sanity developer certification
Track
Sanity developer essentials

Handling schema changes confidently

Lesson
7

Tidy up the schema and front end code

Tidy up the document form by hiding the old field. Update your front end to only query and access the new field name.
Log in to mark your progress for each Lesson and Task

With the successful content migration, you can now clean up the event document type and the front end query.

For real projects, you can either remove the field completely or add hidden: true to hide it from content creators, keep its presence in code in cases where legacy data might enter the dataset, and you want to prevent the “unknown field” warning.

Remove the eventType field in eventType.ts or add hidden: true to hide it visually for content creators.
schemaTypes/eventType.ts
defineField({
name: 'eventType',
type: 'string',
title: 'Event type',
deprecated: {
reason: 'Use the "Event format" field instead.',
},
readOnly: true,
hidden: true, // hide from content creators, but keep it in code
options: {
list: ['in-person', 'virtual'],
layout: 'radio',
},
}),
Remove the "eventType": coalesce(format, eventType) line in the GROQ query
Replace the event.eventType variable in your front end with the new event.format variable.

Note that if you have used this same front end code for Typed content with Sanity TypeGen your query and components may look a little different. Adapt as required!

src/app/events/[slug]/page.tsx
// From the Next.js code example
import { PortableText } from "@portabletext/react";
import { SanityDocument } from "next-sanity";
import imageUrlBuilder from "@sanity/image-url";
import { SanityImageSource } from "@sanity/image-url/lib/types/types";
import { client } from "@/sanity/client";
import Link from "next/link";
const EVENT_QUERY = `*[
_type == "event" &&
slug.current == $slug
][0]{
...,
headline->,
venue->
}`;
const { projectId, dataset } = client.config();
export const urlFor = (source: SanityImageSource) =>
projectId && dataset
? imageUrlBuilder({ projectId, dataset }).image(source)
: null;
export default async function EventPage({
params,
}: {
params: { slug: string };
}) {
const event = await client.fetch<SanityDocument>(EVENT_QUERY, params);
const {
name,
date,
headline,
image,
details,
format,
doorsOpen,
venue,
tickets,
} = event;
const eventImageUrl = image?.asset ? urlFor(image)?.url() : null;
const artistImageUrl = headline?.photo?.asset
? urlFor(headline.photo)?.url()
: null;
const eventDate = new Date(date).toDateString();
const eventTime = new Date(date).toLocaleTimeString();
const doorsOpenTime = new Date(
new Date(date).getTime() + doorsOpen * 60000
).toLocaleTimeString();
return (
<main className="w-full min-h-screen py-12 md:py-24 lg:py-32">
<div className="container px-4 md:px-6 mx-auto">
<div className="mb-4">
<Link href="/">← Back to events</Link>
</div>
<div className="grid items-top gap-6 lg:grid-cols-[1fr_500px] lg:gap-12 xl:grid-cols-[1fr_550px]">
{(eventImageUrl || artistImageUrl) && (
// eslint-disable-next-line @next/next/no-img-element
<img
alt="Image"
className="mx-auto aspect-video overflow-hidden rounded-xl object-cover object-center sm:w-full"
height="310"
src={eventImageUrl || artistImageUrl || ""}
width="550"
/>
)}
<div className="flex flex-col justify-center space-y-4">
<div className="space-y-2">
{format && (
<div className="inline-block rounded-lg bg-gray-100 px-3 py-1 text-sm dark:bg-gray-800 capitalize">
{format.replace("-", " ")}
</div>
)}
{name && (
<h1 className="text-3xl font-bold tracking-tighter sm:text-5xl">
{name}
</h1>
)}
{headline?.name && (
<dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base">
<div className="flex items-start">
<dt className="sr-only">Artist</dt>
<dd className="font-semibold">Artist</dd>
</div>
<div className="grid gap-1">
<dt>{headline?.name}</dt>
</div>
</dl>
)}
<dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base">
<div className="flex items-start">
<dt className="sr-only">Date</dt>
<dd className="font-semibold">Date</dd>
</div>
<div className="grid gap-1">
{eventDate && <dt>{eventDate}</dt>}
{eventTime && <dt>{eventTime}</dt>}
</div>
</dl>
{doorsOpenTime && (
<dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base">
<div className="flex items-start">
<dt className="sr-only">Doors Open</dt>
<dd className="font-semibold">Doors Open</dd>
</div>
<div className="grid gap-1">
<dt>Doors Open</dt>
<dt>{doorsOpenTime}</dt>
</div>
</dl>
)}
<dl className="grid grid-cols-2 gap-1 text-sm font-medium sm:gap-2 lg:text-base">
<div className="flex items-start">
<dt className="sr-only">Venue</dt>
<dd className="font-semibold">Venue</dd>
</div>
<div className="grid gap-1">
<dt>{venue.name}</dt>
<dt>
{venue.city}, {venue.country}
</dt>
</div>
</dl>
</div>
{details && details.length > 0 && (
<div className="prose max-w-none">
<PortableText value={details} />
</div>
)}
{tickets && (
<div className="flex gap-4">
<a
className="inline-flex h-10 items-center justify-center rounded-md bg-gray-900 w-1/2 text-sm font-medium text-gray-50 shadow transition-colors hover:bg-gray-900/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-950 disabled:pointer-events-none disabled:opacity-50 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-50/90 dark:focus-visible:ring-gray-300"
href={tickets}
>
Buy Tickets
</a>
</div>
)}
</div>
</div>
</div>
</main>
);
}
You have 3 uncompleted tasks in this lesson
0 of 3