Choose Theme

Type-Safe Supabase Queries

· 2 min read · #Supabase #TypeScript
--

Generate TypeScript types from your Supabase database and get full type inference for queries.

Generate types:

Terminal window
npx supabase gen types typescript --project-id YOUR_PROJECT_ID > src/types/database.types.ts

Create typed client:

src/lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
import type { Database } from '../types/database.types';
export const supabase = createClient<Database>(
import.meta.env.PUBLIC_SUPABASE_URL,
import.meta.env.PUBLIC_SUPABASE_ANON_KEY
);
// Now all queries are type-safe!

Type-safe queries:

// ✅ TypeScript knows the shape of 'posts'
const { data, error } = await supabase
.from('posts')
.select('id, title, content, author_id, created_at')
.eq('published', true);
if (data) {
data[0].title; // ✅ Type: string
data[0].published; // ✅ Type: boolean
data[0].fake_column; // ❌ Type error!
}
// ✅ Joins are typed too
const { data: postsWithAuthor } = await supabase
.from('posts')
.select(`
id,
title,
author:users(name, email)
`);
if (postsWithAuthor) {
postsWithAuthor[0].author.name; // ✅ Typed!
}
// ✅ Inserts validate against schema
const { data: newPost } = await supabase
.from('posts')
.insert({
title: 'New Post',
content: 'Content here',
published: true,
// fake_field: 'invalid' // ❌ Type error!
})
.select()
.single();

Helper for better inference:

src/lib/database.ts
import { supabase } from './supabase';
import type { Database } from '../types/database.types';
type Tables = Database['public']['Tables'];
// Type-safe table accessor
export function table<T extends keyof Tables>(tableName: T) {
return supabase.from(tableName);
}
// Usage:
const posts = await table('posts').select('*');
const users = await table('users').select('id, name');

Auto-complete and validation:

// IDE auto-completes column names
const { data } = await supabase
.from('posts')
.select('id, ti') // ← Auto-completes to 'title'
.eq('publ') // ← Auto-completes to 'published'
.single();
// Enforces correct types
await supabase.from('posts').insert({
title: 'Valid',
published: 'yes', // ❌ Type error: expected boolean
});

Benefits:

  • Catch typos at compile time
  • Auto-completion for all columns
  • Type-safe joins and relationships
  • Refactoring confidence
  • No runtime overhead

Related