Overview
The official @schmadev/client package provides an idiomatic, lightweight TypeScript client for querying published content from SCHMA. It handles authentication, URL synthesis, query string serialization, environment routing, and JSON response normalization out of the box.
Installation
Install the client package into your project using your preferred package manager:
# npm
npm install @schmadev/client
# pnpm
pnpm add @schmadev/client
# bun
bun add @schmadev/clientInitialize the client
Initialize the client with your Delivery API key and workspace tenant slug. We recommend creating a dedicated client file (e.g. src/lib/schma.ts) to reuse across your application.
import { createClient } from "@schmadev/client";
export const schma = createClient({
apiKey: process.env.SCHMA_DELIVERY_API_KEY!,
tenantSlug: process.env.SCHMA_TENANT_SLUG!,
baseUrl: process.env.SCHMA_API_URL || "https://api.schma.dev",
environment: "production", // optional, defaults to "production"
});| Option | Type | Description |
|---|---|---|
| apiKey | string | () => Promise<string> | Delivery API key with read permissions. |
| tenantSlug | string | Workspace slug (e.g. acme-corp). |
| baseUrl | string | API server URL (defaults to https://api.schma.dev). |
| environment | string | PostgreSQL environment schema (defaults to production). |
Querying content: Delivery methods
The schma.delivery namespace provides methods for querying published entries:
List published entries
Filter, sort, and paginate through entries of a given content model:
// Fetch published blog posts
const { entries, meta } = await schma.delivery.listEntries({
type: "post",
limit: 10,
offset: 0,
sortBy: "createdAt",
order: "desc",
});
console.log(`Fetched ${entries.length} of ${meta.total ?? meta.count} entries`);Get entry by ID
Retrieve a specific published entry by UUID:
// Fetch a single entry by UUID
const post = await schma.delivery.getEntry({
id: "e4b27c62-1a3f-4e89-b765-92c10df48e01",
locale: "en-US", // optional locale
});
console.log(post.title, post.data.content);Semantic similarity search
Perform natural-language vector similarity queries against your published content (available on Pro and Max tiers):
// Semantic vector similarity search (Pro & Max)
const results = await schma.delivery.searchSimilar({
text: "PostgreSQL database configuration and migrations",
limit: 5,
});
for (const entry of results.entries) {
console.log(entry.id, entry.data.title);
}TypeScript end-to-end typing
All delivery methods accept a generic type parameter <T> that flows directly into entry.data:
interface BlogPost {
title: string;
slug: string;
content: string;
publishedDate: string;
author: {
name: string;
avatarUrl?: string;
};
}
// Pass your type to listEntries for end-to-end type safety
const { entries } = await schma.delivery.listEntries<BlogPost>({
type: "post",
limit: 5,
});
entries.forEach((post) => {
// post.data is fully typed as BlogPost
console.log(post.data.title.toUpperCase());
});To generate TypeScript interfaces automatically from your live PostgreSQL schema, use the SCHMA CLI code generator (schma generate).
Framework integration: Next.js App Router
Because @schmadev/client uses standard fetch under the hood, it seamlessly integrates with React Server Components and Next.js caching:
// app/blog/page.tsx (Next.js 15 Server Component)
import { schma } from "@/lib/schma";
interface Article {
title: string;
summary: string;
}
export default async function BlogPage() {
const { entries: articles } = await schma.delivery.listEntries<Article>({
type: "article",
limit: 20,
});
return (
<main className="max-w-4xl mx-auto py-12 px-6">
<h1 className="text-3xl font-bold mb-8">Latest Articles</h1>
<div className="grid gap-6">
{articles.map((item) => (
<article key={item.id} className="p-6 border rounded-lg">
<h2 className="text-xl font-semibold">{item.data.title}</h2>
<p className="text-zinc-400 mt-2">{item.data.summary}</p>
</article>
))}
</div>
</main>
);
}To trigger on-demand cache revalidation when editors publish new content in Studio, set up an ISR webhook handler: