TypeScript SDK for Xata
The Xata SDK supports TypeScript definitions for your Xata database schema. It also works with JavaScript.
It has zero dependencies and can run in Node.js, V8, Deno, and Bun.
We recommend installing the Xata CLI globally and importing the Xata Client from the code generated by the CLI.
When initializing the Xata CLI with the command xata init
in a project, the @xata.io/client
package is installed locally using the current project's package manager. In the event
a package manager can't be determined, the Xata CLI will prompt you to manually install the @xata.io/client
package.
There are three ways to use the SDK:
- Schema-generated Client: SDK to create/read/update/delete records in a given database following a schema file (with type-safety).
- Schema-less Client: SDK to create/read/update/delete records in any database without schema validation (with partial type-safety).
- API Client: SDK to interact with the whole Xata API and all its endpoints.
The TypeScript SDK provides helper methods for creating types based off of Xata client-generated types.
The following are exported on the @xata.io/client
package:
SelectableColumn
provides a type with the valid columns for a record.SelectedPick
returns a subtype of the record with the requested fields.EditableData
removes built-in record methods and reserved fields.
In the example below we create the type myUser
with a selection of fields from the client-generated UserRecord:
import { getXataClient } from './xata';
import { SelectedPick, SelectableColumn, EditableData } from '@xata.io/client';
import { UserRecord } from './xata';
const xata = getXataClient();
const fields: SelectableColumn<UserRecord>[] = ['id', 'name', 'address'];
type myUser = EditableData<SelectedPick<UserRecord, typeof fields>>;
Systems such as Next.js expect the server to send serialized data-structures to the client. Since the Xata SDK returns records as objects as well as strings, there's a need to serialize content for client-side use. Serialization transforms the data into a structured text format that can be easily sent and rebuilt on the client side.
Xata provides the .toSerializable()
method within the record objects to help with serialization. To revert serialized data back to its original types on the client side, you can use the JSONData helper from @xata.io/client
.
An example of a common pattern for this flow in a Next.js system:
import { getXataClient } from './xata';
const xata = getXataClient();
export default async function Page({ params }: { params: { slug: string } }) {
// Pull records from the "users" table
const records = await xata.db.users.getMany();
// Serialize that content, turning any objects into strings
const serializedRecords = records.toSerializable();
// Pass the serialized content to the client component
return <MyComponent records={serializedRecords} />;
}
The MyComponent
client component can then use JSONData
from the client to match against Xata's auto-generated types as shown below.
'use client';
import { FC } from 'react';
import { JSONData } from '@xata.io/client';
import { UserRecord } from './xata';
interface MyComponentProps {
// The data we serialized still matches the UserRecord shape
records: JSONData<UserRecord>;
}
export const MyComponent: FC<MyComponentProps> = ({ records }) => {
return (
<>
{records.map((record) => {
// Date objects were converted to strings during serialization.
// We can always revert them to their original form here in the client, as needed
const date = new Date(record.createdAt);
const dateFormatted = date.toLocaleString();
return <p>{dateFormatted}</p>;
})}
</>
);
};
You should not edit your generated file (e.g. ./src/xata.ts
) since any changes to your schema will cause the file to rebuild when xata codegen
is run. If you need to override the configuration, you can set up a separate file alongside the generated code.
export const getXataClient = () => {
if (instance) return instance;
instance = new XataClient({
// Override configuration here
databaseURL: process.env.XATA_DATABASE_URL,
apiKey: process.env.XATA_API_KEY,
fetch: fetch,
branch: process.env.XATA_BRANCH
// ... other configuration
});
return instance;
};
Some frameworks may not be compatible with parsing credentials from .env
, instead requiring to pass your API key manually with the apiKey
constructor option:
import { XataClient } from './xata';
const xata = new XataClient({ apiKey: XATA_API_KEY });
In case your runtime does not provide a built-in Fetch API (such as with versions prior to Node 18), you will need to pass a fetch implementation to the fetch
constructor parameter of the XataClient in the xata.ts
/ xata.js
file in your project.
The command xata codegen
updates the schema for the Xata client. Applying schema changes from the CLI, such as using the command xata schema edit
, will automatically run codegen to update your client. However, in case schema changes have been applied from the web UI, you should run xata codegen
to update your existing client with the latest schema.
Type recursion is limited to 3 levels in the TypeScript SDK. This is to prevent excessive strain on both the type checker and the language server since each nested level adds computational complexity.
Calls on deeper nested columns will still work, but a TypeScript error may be displayed indicating the type cannot be determined.