How to reference a field from another schema in Sanity?

6 replies
Last updated: May 18, 2021
Is it possible to refer to another field in another schema? For example;

export default {
  name: 'referExample',
  title: 'A reference to another field in another schema',
  description: 'For example, to show an address on this page but have it editable on another document',
  type: 'document',
    {
      name: 'address',
      title: 'Address',
      type: 'text',
      readOnly: true,
      initialValue: REF_TO_FIELD_ID_OR_SOMETHING, // this would somehow reference the 'address' field from the 'settings' page
      description: 'This field is set on the settings page',
    },
  ],
};
AI Update

Based on what you're trying to do, you can't directly reference another field's value from a different document in the way you've described. However, there are a few approaches that can achieve similar results:

You can use an async function in the field's initialValue to fetch data from another document. The initialValue function receives a context object that includes getClient():

{
  name: 'address',
  title: 'Address',
  type: 'text',
  readOnly: true,
  initialValue: async (props, context) => {
    const {getClient} = context
    const client = getClient({apiVersion: '2024-11-01'})
    
    const settings = await client.fetch(
      `*[_type == "settings"][0].address`
    )
    
    return settings
  },
  description: 'This field is set on the settings page',
}

Important caveat: The initialValue only runs when the document is first created. It won't update if the settings document changes later. This is literally an "initial" value, not a live reference.

2. Use a Standard Reference Field

If you want to maintain a live connection to the settings document, use a reference field:

{
  name: 'settingsRef',
  title: 'Settings',
  type: 'reference',
  to: [{type: 'settings'}],
  hidden: true, // Hide it from editors if you always want it to reference settings
}

Then in your queries, you can dereference it to get the address:

*[_type == "referExample"] {
  ...,
  "address": settingsRef->address
}

3. Display-Only: Use a Custom Component

If you just want to display the value from another document in the Studio UI (not actually store it), you can create a custom input component that fetches and displays the value from your settings document. This would be read-only by nature and always show the current value.

4. Use Initial Value Templates

If you're creating documents programmatically or through specific workflows, Initial Value Templates give you more control and context-awareness when setting initial values across multiple fields.

The Key Limitation

Sanity doesn't support "live" field references where one field automatically mirrors another field's value from a different document. This is by design—each document is independent, and relationships are established through reference fields that you dereference at query time.

For your specific use case of showing an address from a settings page, I'd recommend either:

  • Option 1 if you want a snapshot of the address at document creation time
  • Option 2 if you want to query the current address value when you fetch the document
  • Option 3 if you only need to display it in the Studio UI for editor reference
Show original thread
6 replies
The
initialValue
would reference a field from another schema, for example an address, and show it here as a
readOnly
field. This is just for transparency for the client so they can see the address field here too.
Just a further thought… it would be really cool if these settings could be edited two ways. For example, if I changed the data in the ‘findUs.js’ schema/page, it would update the data from ‘settings.js’ schema/page too
This could be done with a document Action overriding the document's publish action.
As for your original question, I think you might want to make an custom input--that will give you the flexibility that you need.
Hi User. Here’s an effort to get you started, though I can’t promise it’s the best approach to this. It also does not perform the update in reverse. There are two document types:
chrish.js
and
chrishResource.js
.

// chrishResource.js

export default {
  name: 'chrishResource',
  type: 'document',
  fields: [
    {
      name: 'address',
      title: 'Address',
      type: 'text',
    },
  ],
};

// chrish.js

import React, { useState, useEffect } from 'react';
import PatchEvent, { set } from 'part:@sanity/form-builder/patch-event';
import FormField from 'part:@sanity/components/formfields/default';
import { TextArea } from '@sanity/ui';
import sanityClient from 'part:@sanity/base/client';

const client = sanityClient.withConfig({ apiVersion: '2021-05-13' });

const AddressInput = React.forwardRef((props, ref) => {
  const { type, onChange } = props;
  const [address, setAddress] = useState();

  useEffect(() => {
    client.fetch(`*[_type == 'chrishResource'][0].address`).then((res) => setAddress(res));
  }, []);

  return (
    <FormField label={type.title} description={type.description}>
      <TextArea
        ref={ref}
        value={address ?? ''}
        readOnly
        rows={type.rows}
        onChange={(event) => {
          onChange(PatchEvent.from(set(event.target.value)));
        }}
      />
    </FormField>
  );
});

AddressInput.displayName = 'AddressInput';

export default {
  name: 'referExample',
  title: 'A reference to another field in another schema',
  type: 'document',
  fields: [
    {
      name: 'title',
      type: 'string',
    },
    {
      name: 'address',
      title: 'Address',
      type: 'text',
      rows: 4,
      inputComponent: AddressInput,
      description: 'This field is set on the settings page',
    },
  ],
};
The query you set in useEffect would dictate what address you get back.
Hey
user A
thanks so much for your reply. I didn’t see this until now but this is really helpful 🙂

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?