Sanity-codegen query with projection not working as expected

17 replies
Last updated: Feb 11, 2021
Does anybody have experience with using sanity-codegen ? I feel like the query below should work. It works if I just use
*[_type == "country"]
but then it selects all of the values.
const allCountries = await client.query(
  '*[_type == "country"] { \'slug\': slug.current }'
);
AI Update

Your GROQ query *[_type == "country"] { 'slug': slug.current } is perfectly valid syntax and should work fine with sanity-codegen's client! The query itself isn't the problem.

However, I need to give you some important context: sanity-codegen has been archived and is no longer actively maintained. It's been superseded by Sanity's official TypeGen tooling, which was released in March 2024.

Without seeing the specific error you're getting, here are the most likely issues:

If you're getting type errors: The sanity-codegen client's query<T>() method should handle projections, but you might need to explicitly type the result:

interface CountrySlug {
  slug: string;
}

const allCountries = await client.query<CountrySlug[]>(
  '*[_type == "country"] { "slug": slug.current }'
);

Note: Use "slug" (with quotes) instead of 'slug' in your projection - both work in GROQ, but double quotes are the standard convention.

Recommended: Migrate to Official TypeGen

Since sanity-codegen is archived, I'd strongly recommend migrating to the official solution. It provides better type inference and is actively maintained:

npx sanity@latest typegen generate

Then use defineQuery for automatic type inference:

import { defineQuery } from 'next-sanity'; // or 'groq'
import { sanityFetch } from './lib/client';

const COUNTRIES_QUERY = defineQuery(
  '*[_type == "country"] { "slug": slug.current }'
);

const allCountries = await sanityFetch({ query: COUNTRIES_QUERY });
// TypeScript automatically knows the shape!

The official TypeGen creates a sanity.types.ts file with types for your entire schema and automatically infers types from your GROQ queries - no manual type annotations needed.

If you want to stick with sanity-codegen for now, can you share the specific error message you're seeing? That would help diagnose whether it's a type issue, runtime error, or something else.

Show original thread
17 replies
When you query without the projection (i.e., just
*[_type == "country"]
) is
slug
at the top-level?
Yes
i actually think this is a bug in my code šŸ˜…
Aha, that explains it! I have been confused with this for a while now šŸ˜‚
yeah apologies. to be frank, the sanity-codegen client is somewhat less stable than the codegen itself.
the codegen client is just a decent way to get automatic types with a relatively easy implementation but a real implementation of a codegen client would involve parsing groq queries and mapping projections from the codegen’ed schema types
so besides bundle size, you’ll really so no improvements over
@sanity/client
for
cilent.query
Ok thanks. My application is fairly simple so i’m not sure if I need anything particularly fancy. Would
@sanity/client
work with the generated types? I’ve not looked into it much yet
it does but you’ll have to import the codegen types yourself and add them as a type parameter
e.g.


import * as Schema from '../codegen-output';

// e.g.
client.fetch<Schema.BlogPost[]>('*[ _type === 'blogPost' ]');
this would pair well with typescript’s utility types: https://www.typescriptlang.org/docs/handbook/utility-types.html
e.g.
client.fetch<Pick<Schema.BlogPost, 'title'>[]>('*[ _type === 'blogPost' ] { title }');
Ok so i’ve tried this using
@sanity/client
and it seems to work…
  const allCountries = await client.fetch<Country[]>(
    '*[_type == "country"] {_id, slug, name}'
  );
Would
Country[]
or just
Country
make sense there, seems like both work for me?
it would be
Pick<Country, '_id' | 'slug' | 'name'>[]
Thanks for your help man, really appreciate it. I’m relatively new to TS so it’s a bit of a challenge
Of course. I think i’ll update the docs with some of this feedback too. I think it’ll really help others who are in the same boat.
My eventual goal is to get it to where it just generates the rights types for you automatically but I’m not quite there yet
That would be nice and I would help get to that point if I had the ability šŸ˜‚

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?