SDK Quickstart
Install the SDK
Add the Monospace SDK to your project.
npm install @monospace/sdk
This installs the SDK client, CLI, and type generator. You also need TypeScript with strict mode enabled:
{
"compilerOptions": {
"strict": true
}
}
Initialize Configuration
Run the interactive setup wizard to create a config file.
npx @monospace/sdk init
The wizard prompts for your instance URL and project identifier, then writes a monospace.config.ts file:
import { defineConfig } from '@monospace/sdk/config'
export default defineConfig({
url: 'https://example.monospace.io',
project: 'blog',
output: './src/generated/monospace',
})
output is where the generated typed client will live. The default is ./src/generated/monospace.
Generate Types
Run the generator to introspect your Monospace instance and produce a typed client.
npx @monospace/sdk generate
The generator connects to your instance, reads the schema via the OpenAPI endpoint, and writes a single index.ts file:
your-project/
├── src/
│ └── generated/
│ └── monospace/
│ └── index.ts ← generated typed client
├── monospace.config.ts
├── package.json
└── tsconfig.json
The generated file contains:
- TypeScript types for every collection, including field types, filter inputs, and relation shapes
- A pre-typed
createClientfactory with yourSchemabaked in — no manual generic parameters needed - Per-collection type aliases like
ArticleKey,ArticleCreateOneInput,ArticleReadManyResult, and more
MONOSPACE_API_KEY in a .env file, or run npx @monospace/sdk login to authenticate via the OS keychain.Create the Client
Import createClient from the generated output — not from @monospace/sdk directly. The generated factory already knows your schema.
import { createClient } from './generated/monospace';
const client = createClient({
url: 'https://example.monospace.io',
project: 'blog',
apiKey: process.env.MONOSPACE_API_KEY,
});
That's it. client is now a fully typed Monospace client. Every collection in your schema is available as a property — client.Articles, client.Authors, client.Tags — with autocomplete for every CRUD method and field name.
This is the payoff of the codegen step. Type client. in your editor and you should see every collection listed. Select one, type .readMany({ fields: [ and your field names appear as autocomplete suggestions. No manual type definitions, no runtime validation — the types come directly from your schema.
Read Your Data
Fetch articles with typed field selection.
const articles = await client.Articles.readMany({
fields: ['id', 'title', 'status'],
});
// TypeScript knows the exact shape:
// {
// id: string | null;
// title: string | null;
// status: string | null;
// }[]
for (const article of articles) {
console.log(article.title);
}
The return type narrows to match your fields array. Request three fields, get three fields in the type. Add a field, the type updates. Remove one, TypeScript flags any code that references it.
readMany returns up to 100 items by default. Use limit and offset for pagination:
const page = await client.Articles.readMany({
fields: ['id', 'title'],
limit: 20,
offset: 40,
});
Fetch a single item by key:
const article = await client.Articles.readOne({
key: 1,
fields: ['id', 'title', 'status'],
});
// TypeScript infers a single object (not an array):
// {
// id: string | null;
// title: string | null;
// status: string | null;
// }
Create and Update Items
Create an article with typed input validation.
const created = await client.Articles.createOne({
data: {
title: 'Getting Started with Monospace',
status: 'draft',
},
fields: ['id', 'title', 'status'],
});
console.log(created.id); // typed as string | null
The data object is typed against your schema — TypeScript enforces required fields and rejects unknown properties.
Update an existing article by key:
const updated = await client.Articles.updateOne({
key: created.id,
data: {
status: 'published',
},
fields: ['id', 'status'],
});
console.log(updated.status); // typed as string | null
Update inputs make every field optional — include only the fields you want to change.
Next Steps
- Filtering — narrow results with typed filter operators like
_eq,_contains, and_in - Field Selection — control which fields are returned, including nested relations
- Relational Data — fetch and write nested relations in a single request
- Type System — extract result types for component props, reusable queries with
satisfies, and more