Best practice validations for common Sanity field types

6 replies
Last updated: Mar 16, 2022
Curious if anyone has a list of “best practice” validations for different types of fields (slugs, titles, etc.)?
AI Update

Great question! While validation rules are often project-specific, there are definitely some common patterns the Sanity community has established, especially for fields like slugs.

General Validation Philosophy

As the community discussion points out, most validation is heavily dependent on your team and business needs. However, certain field types like slugs have more established web standards around them (lowercase, kebab-case formatting).

Slug Validation Best Practices

For slugs specifically, check out Simeon Griggs' excellent tutorial on Next.js and Sanity slug patterns - it's widely used in production projects.

Here's a solid slug configuration with custom slugification:

defineField({
  name: 'slug',
  title: 'Slug',
  type: 'slug',
  options: {
    source: 'title',
    slugify: input => input
      .toLowerCase()
      .replace(/\s+/g, '-')
      .replace(/[^\w\-]+/g, '')
      .replace(/\-\-+/g, '-')
      .replace(/^-+/, '')
      .replace(/-+$/, '')
      .slice(0, 200)
  },
  validation: (rule) => rule.required()
})

Common Validation Patterns by Field Type

Titles

defineField({
  name: 'title',
  title: 'Title',
  type: 'string',
  validation: (rule) => rule
    .required()
    .min(10)
    .max(100)
    .error('Title must be between 10 and 100 characters')
})

Meta Descriptions (SEO)

defineField({
  name: 'metaDescription',
  title: 'Meta Description',
  type: 'text',
  validation: (rule) => rule
    .max(160)
    .warning('Keep under 160 characters for optimal SEO')
})

Email Fields

defineField({
  name: 'email',
  type: 'string',
  validation: (rule) => rule.custom((email) => {
    if (!email) return true
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return regex.test(email) ? true : 'Please enter a valid email address'
  })
})

URLs

defineField({
  name: 'externalUrl',
  type: 'url',
  validation: (rule) => rule.uri({
    scheme: ['http', 'https']
  })
})

Required Fields with Context

defineField({
  name: 'publishDate',
  type: 'datetime',
  validation: (rule) => rule.custom((value, context) => {
    if (context?.document?.status === 'published' && !value) {
      return 'Publish date is required for published content'
    }
    return true
  })
})

Key Validation Features

The Sanity validation system supports three severity levels:

  • Errors: Block publishing (use .error())
  • Warnings: Allow publishing but flag issues (use .warning())
  • Info: Provide helpful context (return string from .custom())

Important Considerations

  1. Client-side only: Validation currently only runs in the Studio. If you're using the API directly, implement server-side validation separately.

  2. Title auto-generation: As mentioned in the defineField documentation, Sanity auto-generates titles from field names, but doesn't handle special cases well. Always explicitly set titles for acronyms (URL, SEO) and brand names (LinkedIn, GitHub).

  3. Descriptions matter: Use the description property to explain why validation rules exist - it helps your content team understand the requirements.

The community thread also had a creative example of prepending random hex strings to slugs for guaranteed uniqueness, though that's typically unnecessary for most use cases unless you have specific requirements around collision avoidance.

What specific field types are you working with? The validation system is quite flexible and can handle pretty much any custom logic you need!

Show original thread
6 replies
I would say for most things it could be heavily dependant on the team/business, but for certain things like slugs for example which have a bit more ‘standards’ around in the web anyway is that they should be lowercase and kebab-case.
Certain things around words aka Titles etc will be very subjective and I doubt there would be much common expectations around them
Yeah, that makes sense when you say it like that
There's an incredible tutorial put out by Simeon Griggs with URL's that we use on pretty much every project
Fantastic, will check it out! Thanks
One of the cool things in the studio is using it as a way to practice different js ideas and get immediate results. This is totally unnecessary for nearly any real use case and likely can be written cleaner, but it was a fun experiment with js objects and regex in a schema.
I wanted to try to get more granular control of the included slug function along with prepended a small hex string. Maybe it can give you some inspiration:
insert hex:



function slugHex() {
  function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min) + min);
  }
  // hex 5 digits: [10000-fffff]
  let x = 65536
  let y = 1048575
  return (getRandomInt(x,y).toString(16) + '-')
}
call it in the schema:



{
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'title',
        slugify: input => input
            .toLowerCase()
            .replace(/^/, slugHex())
            .replace(/\s+/g, '-')
            .replace(/[^\w\-]+/g, '')
            .replace(/\-\-+/g, '-')
            .replace(/^-+/, '') 
            .replace(/-+$/, '')
            .slice(0, 101)
      },

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?