Get Started with Tento

Build by drizzle team

Tento - is simple yet powerful API for working with Shopify data, including metaobjects, metafields and products. It also provides a CLI tool for two-way synchronization between your local schema definition and Shopify.

This guide assumes familiarity with:
  • @shopify/shopify-api - package for access for the Shopify Admin API - read here
  • dotenv - package for managing environment variables - read here
  • tsx - package for running TypeScript files - read here
  • Understanding of Shopify Metaobject instance - read here
  • Understanding of Shopify Metafield instance - read here
  • Get started with OAuth - read here
  • Migrations tento.config.ts fundamentals - read here

Step 1 - Install dependencies

npm
yarn
pnpm
bun
npm i @drizzle-team/tento

Step 2 - Setup connection variables

Create a .env file in the root of your project and add your Shopify Access Token variable:

SHOPIFY_ACCESS_TOKEN=
SHOPIFY_SHOP_ID=

Step 3 - Declare schema file

Create a schema.ts file and declare your metaobjects and metafields schema:

info

As of now Tento only supports one schema file.

src/db/schema.ts
import { metaobject, metafield } from '@drizzle-team/tento';

export const description = metafield({
  name: "Description",
  key: "description",
  namespace: "custom",
  ownerType: "PRODUCT",
  fieldDefinition: (f) => f.multiLineTextField(),
});

export const designer = metaobject({
  name: "Designer",
  type: "designer",
  fieldDefinitions: (f) => ({
    name: f.singleLineTextField({
      name: "Title",
      required: true,
      validations: (v) => [v.min(1), v.max(50)],
    }),
    description: f.multiLineTextField({
      name: "Description",
    }),
    website: f.url({
      name: "Website",
    }),
  }),
});

Step 4 - Connect Tento client

Create a index.ts file and initialize the connection:

src/index.ts
import 'dotenv/config';
import '@shopify/shopify-api/adapters/web-api';
import * as schema from './db/schema';
import { createClient, tento } from '@drizzle-team/tento';

const client = tento({
  client: createClient({
    shop: process.env.SHOPIFY_SHOP_ID!,
    headers: {
      "X-Shopify-Access-Token": process.env.SHOPIFY_ACCESS_TOKEN!,
    },
  }),
  schema,
});

Step 5 - Setup Tento config file

Tento config - a configuration file that is used by Tento CLI and contains all the information about your Shopify connection and schema files.

Create a tento.config.ts file in the root of your project and add the following content:

tento.config.ts
import 'dotenv/config';
import { defineConfig } from "@drizzle-team/tento/cli";

export default defineConfig({
  schemaPath: './src/schema.ts',
  shop: process.env.SHOPIFY_SHOP_ID!,
  headers: {
    'X-Shopify-Access-Token': process.env.SHOPIFY_ACCESS_TOKEN!,
  },
});

Step 6 - Applying changes to the Shopify

You can directly apply changes to your Shopify store using the tento push command, or using client method applySchema():

CLI
Client
npx tento push

Read more about migration process in documentation.

Step 7 - Query the Shopify

Let’s update the src/index.ts file with queries to create, read, update, and delete designers

src/index.ts
import 'dotenv/config';
import '@shopify/shopify-api/adapters/web-api';
import * as schema from './db/schema';
import { createClient, tento } from '@drizzle-team/tento';

const client = tento({
  client: createClient({
    shop: process.env.SHOPIFY_SHOP_ID!,
    headers: {
      "X-Shopify-Access-Token": process.env.SHOPIFY_ACCESS_TOKEN!,
    },
  }),
  schema,
});

async function main() {
  await client.applySchema();

  const designer: typeof client.metaobjects.designer.$inferInsert = {
    name: "John",
    description: "John is designer",
    website: "",
  };

  const createdDesigner = await client.metaobjects.designer.insert(designer);
  console.log("New designer created!");

  const designers = await client.metaobjects.designer.list({
    first: 50
  });
  console.log('Getting first 50 designers from the Shopify: ', designers)
  /*
  const designers: {
    items: {
      _id: string;
      _handle: string;
      _displayName: string;
      _updatedAt: Date;
      name: string;
      description: string | null;
      website: string | null;
    }[];
    pageInfo: {
      startCursor: string;
      endCursor: string;
      hasNextPage: boolean;
      hasPreviousPage: boolean;
    };
  }
  */

  await client.metaobjects.designer.update(createdDesigner._id, {
    fields: {
      description: "John is designer!",
    },
  });
  console.log("Designer info updated");

  await client.metaobjects.designer.delete(createdDesigner._id);
  console.log("Designer deleted");
}

Step 8 - Run index.ts file

To run any TypeScript files, you have several options, but let’s stick with one: using tsx

You’ve already installed tsx, so we can run our queries now

Run index.ts script

npm
yarn
pnpm
bun
npx tsx src/index.ts