Skip to main content

3 posts tagged with "typescript"

View All Tags

ยท 7 min read
Himank Chaudhary

Search is a fundamental part of an application especially when we build retail and e-commerce applications. Search provides your customers a great shopping experience. This blog will demonstrate how Tigris makes it super easy to add real-time and relevance-based search to your application. Tigris has an embedded search engine which automatically makes all your data searchable.

Tigris + NuxtJS

The article will be focusing mainly on integrating full-text search capabilities using Tigris and Nuxt.js and may skip over few things like styling etc. which will be pre-generated in the template used for this tutorial.

Here is a link to working example of this e-commerce store that you will build. The source code is available on GitHub repo if you feel like exploring on your own, else follow along the tutorial.


You'll need a few things installed

Getting Startedโ€‹

The first step is to clone the repository that contains the starting source code.

git clone -b ecommerce-search-scaffold

cd into the project directory

cd tigris-netlify-ecommerce

The layout of this project is like below.

โ”œโ”€โ”€ package.json
โ””โ”€โ”€ pages
โ”œโ”€โ”€ all.vue
โ”œโ”€โ”€ cart.vue
โ”œโ”€โ”€ index.vue
โ”œโ”€โ”€ women.vue
โ””โ”€โ”€ men.vue
โ””โ”€โ”€ layouts
โ”œโ”€โ”€ default.vue
โ””โ”€โ”€ static
โ”œโ”€โ”€ storedata.json
โ””โ”€โ”€ functions
โ”œโ”€โ”€ read-all-products.ts
โ”œโ”€โ”€ create-payment-intent.ts
โ””โ”€โ”€ handle-payment-succeeded.ts
โ”œโ”€โ”€ models
โ”‚ โ””โ”€โ”€ tigris
โ”‚ โ””โ”€โ”€ catalog
โ”‚ โ””โ”€โ”€ products.ts
โ””โ”€โ”€ store
โ””โ”€โ”€ index.js
  • package.json - Configuration for the Node project
  • pages/ - This is where all the vue files that encapsulate the template, logic, and styling of a Vue component
  • functions/ - All serverless functions(API endpoints) for the application are defined in this directory
  • models/tigris/catalog/ - To manage schema of this application. Database is catalog and collection is products
  • store/ - Vuex store

Create a database, collection and load the datasetโ€‹

We will connect to Tigris Cloud to run this application. Let's first create an application key for your project to get TIGRIS_CLIENT_ID and TIGRIS_CLIENT_SECRET.

tigris create application ecommerce_search "search tutorial"
"id": "dummy-id",
"name": "ecommerce_search",
"description": "search tutorial",
"secret": "dummy-secret",
"created_at": 1668493288000,
"created_by": "google-oauth2|107496644751065904534"

Once done, you can create a .env and copy "id" to TIGRIS_CLIENT_ID and "secret" to TIGRIS_CLIENT_SECRET from above.

TIGRIS_CLIENT_ID=<copy id from above>
TIGRIS_CLIENT_SECRET=<copy secret from above>

After this just run the load target and that will automatically create your database and collection and will load the data present here.

npm run load
> ecommerce-netlify@1.0.0 load
> npm run setup:dev

> ecommerce-netlify@1.0.0 setup:dev
> NODE_ENV=development npm run setup

> ecommerce-netlify@1.0.0 setup
> npx ts-node scripts/setup.ts

event - Scanning /Users/himank/tigris-netlify-ecommerce/models/tigris for Tigris schema definitions
info - Found DB definition catalog
info - Found Schema file products.ts in catalog
info - Found schema definition: ProductSchema
debug - Generated Tigris Manifest: [{"dbName":"catalog","collections":[{"collectionName":"products","schema":{"id":{"type":"string","primary_key":{"order":1}},"color":{"type":"string"},"description":{"type":"string"},"gender":{"type":"string"},"name":{"type":"string"},"review":{"type":"string"},"starrating":{"type":"number"},"price":{"type":"number"},"sizes":{"type":"array","items":{"type":"string"}},"img":{"type":"string"}},"schemaName":"ProductSchema"}]}]
event - Created database: catalog
debug - {"title":"products","additionalProperties":false,"type":"object","properties":{"id":{"type":"string"},"color":{"type":"string"},"description":{"type":"string"},"gender":{"type":"string"},"name":{"type":"string"},"review":{"type":"string"},"starrating":{"type":"number"},"price":{"type":"number"},"sizes":{"type":"array","items":{"type":"string"}},"img":{"type":"string"}},"collection_type":"documents","primary_key":["id"]}
event - Created collection: products from schema: ProductSchema in db: catalog
Inserted 30 documents
Setup complete ...

Add full-text search capabilitiesโ€‹

To add full-text search to our application, we only need to perform three steps:

  • Serverless functions to call Tigris search
  • Async action in vuex store to call Tigris search serverless function
  • Search vue to have search text in the UI

Let's write a serverless function to add search functionality to the e-commerce store. This serverless function will be used by the vuex store to power search functionality for the application.

โŒฒ Add the following code inside functions/search-products.ts.โ€‹

import { Handler } from "@netlify/functions";
import { Tigris } from "@tigrisdata/core";
import { Product } from "~/models/tigris/catalog/products";

const tigris = new Tigris();

const handler: Handler = async (event, context) => {
const searchReq = JSON.parse(event.body);

if (!searchReq.q) {
console.log("search keyword is missing");
return {
statusCode: 400,
body: JSON.stringify({
status: "search keyword is missing",

try {
const products = tigris

const searchResult = await;

const productHits = new Array();
for (const hit of searchResult.hits) {
return {
statusCode: 200,
body: JSON.stringify(productHits),
} catch (err) {
return {
statusCode: 500,
body: JSON.stringify({
status: err,

export { handler };

The main thing to note in the above serverless function is that we are simply calling search on the product collection.

Step2: Integrate Search Serverless functions in vuex storeโ€‹

The next step is to integrate the serverless function that we have just added above in the vuex store. Here we will be adding an async action searchProducts. As you can notice in the following code that this async action is passing the keyword to the serverless function that we have added above. This keyword is the text that user wants to search in the application. We will see in Step3 on how the vue is passing the text to this async action.

โŒฒ Add the following code inside actions export const actions = {...} in store/index.tsโ€‹

async searchProducts({ commit }, keyword) {
try {
const response = await
q: keyword,
headers: {
"Content-Type": "application/json"
if ( {
} catch (e) {
console.log("error", e);

The next step is to update the mutations based on the actions that we have added. Add the searchProducts in the export const mutations = {...} by adding the following code.

searchProducts: (state, payload) => {
state.searchdata = payload;

Note: Add a new variable "searchdata" in the state so that mutations can update it.

Add a searchResult inside getters export const getters = {...} to access search results

searchResult: (state) => state.searchdata;

Step3: Search vue to have search text in the UIโ€‹

Create a vue file and add the following code to it.

<div class="searchHeader">
<input type="text" v-model="keyword" placeholder="Search Keyword" />
:disabled="loading || !keyword"
>{{(!loading) ? 'Search Products' : 'Loading...'}}</button>

<p class="noResults" v-if="usingSearch && !loading && searchResult.length<1">No results found..</p>

<app-store-grid :data="(usingSearch) ? searchResult : storedata" />
import AppStoreGrid from "~/components/AppStoreGrid.vue"
import { mapGetters, mapState } from 'vuex';
export default {
components: {
computed: {
data() {
return {
keyword: "",
error: "",
loading: false,
usingSearch: false,
methods: {
search() {
this.loading = true;
this.usingSearch = true;
this.$store.dispatch("searchProducts", this.keyword).
then(() => {
this.loading = false;

<style lang="scss" scoped>
.noResults {
text-align: center;
.searchBtn {
width: 180px;
.searchHeader {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 40px;

Now, add this search.vue to the AppNav.vue component.

<nuxt-link to="/search">Search</nuxt-link>

At this point, you have successfully integrated Search in your application. You can also check out the full code here.

Run the appโ€‹

Let's reap the rewards. Run netlify dev using netlify CLI in terminal.

You should see following output:

netlify dev
โ—ˆ Netlify Dev โ—ˆ
โ—ˆ Ignored netlify.toml file env var: TIGRIS_URI (defined in .env file)
โ—ˆ Injected .env file env var: TIGRIS_URI
โ—ˆ Ignored general context env var: LANG (defined in process)
โ—ˆ Injected .env file env var: TIGRIS_CLIENT_ID
โ—ˆ Injected .env file env var: TIGRIS_CLIENT_SECRET
โ—ˆ Loaded function create-payment-intent.
โ—ˆ Loaded function handle-payment-succeeded.
โ—ˆ Loaded function read-all-products.
โ—ˆ Functions server is listening on 50405
โ—ˆ Setting up local development server

Netlify Build

โฏ Version
@netlify/build 27.20.1

โฏ Flags

โฏ Current directory

โฏ Config file

โฏ Context

1. Run command for local development

โ—ˆ Starting Netlify Dev with Nuxt 2
yarn run v1.22.19
warning ../package.json: No license field
$ nuxt dev
โ„น Listening on: http://localhost:3000/
โ„น Preparing project for development
โ„น Initial build may take a while
โœ” Builder initialized
โœ” Waiting for framework port 3000. This can be configured using the 'targetPort' property in the netlify.toml

(dev.command completed in 2s)
โœ” Nuxt files generated

โ”‚ โ”‚
โ”‚ โ—ˆ Server now ready on http://localhost:8888 โ”‚
โ”‚ โ”‚

Voila! there you have it. E-commerce store is accessible on http://localhost:8888 on your browser, go ahead and play around.


Tigris has an embedded search engine which automatically makes all your data searchable. This blog demonstrated that adding search functionality in your application using Tigris search is super easy, and everything happened in the code. You can also check out this product catalog in Tigris console.

ยท One min read
Adil Ansari

Happy to announce that Next.js now has an officially supported example for bootstrapping your projects using Tigris. Creating a project with Next.js and Tigris is as simple as:

$ npx create-next-app --example with-tigris

Getting startedโ€‹

Next.js allows you to bootstrap Next.js apps using create-next-app utility.

Install Tigrisโ€‹

Startup Tigris dev environmentโ€‹

$ tigris dev start

Initialize your Next.js appโ€‹

Use the official create-next-app utility

$ npx create-next-app --example with-tigris
$ โž”  npx create-next-app --example with-tigris
โœ” What is your project named? โ€ฆ my-tigris-app
Creating a new Next.js app in ./my-tigris-app.

Downloading files for example with-tigris. This might take a moment.

Installing packages. This might take a couple of minutes.

added 67 packages, and audited 68 packages in 4s

5 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities

Initialized a git repository.

Success! Created my-tigris-app at ./my-tigris-app
Inside that directory, you can run several commands:

npm run dev
Starts the development server.

npm run build
Builds the app for production.

npm start
Runs the built app in production mode.

We suggest that you begin by typing:

cd my-tigris-app
npm run dev

Run the appโ€‹

Run the app and see it will automatically create your databases and collections.

$ cd my-tigris-app
$ npm run dev
$ โž”  cd my-tigris-app
$ โž” npm run dev ยฑ[main]

> predev
> APP_ENV=development npm run setup

> setup
> npx ts-node scripts/setup.ts

Loaded env from ./my-tigris-app/.env.development
event - Scanning ./my-tigris-app/models/tigris for Tigris schema definitions
info - Found DB definition todoStarterApp
info - Found Schema file todoItems.ts in todoStarterApp
info - Found schema definition: TodoItemSchema
debug - Generated Tigris Manifest: [{"dbName":"todoStarterApp","collections":[{"collectionName":"todoItems","schema":{"id":{"type":"int32","primary_key":{"order":1,"autoGenerate":true}},"text":{"type":"string"},"completed":{"type":"boolean"}},"schemaName":"TodoItemSchema"}]}]
event - Created database: todoStarterApp
debug - {"title":"todoItems","additionalProperties":false,"type":"object","properties":{"id":{"type":"integer","format":"int32","autoGenerate":true},"text":{"type":"string"},"completed":{"type":"boolean"}},"collection_type":"documents","primary_key":["id"]}
event - Created collection: todoItems from schema: TodoItemSchema in db: todoStarterApp

> dev
> next dev

ready - started server on, url: http://localhost:3000
info - Loaded env from ./my-tigris-app/.env.development
event - compiled client and server successfully in 856 ms (154 modules)

ยท 9 min read
Adil Ansari
Taha Khan

Next.js gives you the best developer experience with all the features you need to build modern, fast production-ready applications. Tigris is the perfect companion for Next.js as it is similarly built with developer experience in mind and is truly serverless: build data-rich features, seamlessly implement search, and easily use it with serverless functions, all without needing to do Ops.

Next.js and Tigris

Now with the introduction out of the way, it is time to demonstrate how.

This is the first of a series of blog posts where we will demonstrate how easy it is to build Next.js apps with Tigris. We will build a to-do list app and deploy it to Vercel. The to-do list app will have the following features:

  • add to-do items to the list
  • update to-do items as completed
  • delete to-do items
  • search for to-do items in the list

To follow along with this tutorial you can get the code from the GitHub repo. This is how the to-do app will look once its deployed:


For this tutorial you'll need:

  1. GitHub account (sign up for free)
  2. Tigris Cloud account (sign up for free)
  3. Vercel account (sign up for free) to deploy app
  4. Node.js 16+
  5. npm and npx

Deploying the to-do list app to Vercelโ€‹

We will start off first by deploying the pre-prepared to-do list app to Vercel from the GitHub repo. Then once it is deployed and running, we will explore the code in detail.

Create a project on Vercelโ€‹

Vercel makes it easier to deploy Git projects with a few clicks.

Hit the following Deploy button to get started with the Vercel workflow to clone the repo to your account

Deploy with Vercel

This should take you to Vercel to the "Create Git Repository" step

Vercel create repo

Add Tigris integrationโ€‹

Pick a name for your new Git repo and then you'll configure the Tigris integration that will setup the environment variables needed to connect to Tigris: TIGRIS_URI, TIGRIS_CLIENT_ID, and TIGRIS_CLIENT_SECRET.

Vercel environment

Hit the Add button and it will take you to the Tigris integration page where in few simple steps you will be able to configure the integration.

Vercel integrate Tigris

Hit the Continue button and that's it!

Once the deployment completes, continue to your project dashboard on Vercel where you'll find URL for your to-do list app

Vercel project dashboard

๐ŸŽ‰ All done. Visit the URL in browser to access your to-do list app and play around. ๐ŸŽ‰

Now let's continue to explore the code for the to-do list app to see how easily Tigris can be integrated with Next.js.

Code walk-throughโ€‹

This section will elaborate on important aspects of the to-do list app you just deployed. Let's glance over the important components of the project.

File structure
|-- package.json
|-- lib
|-- tigris.ts
|-- models
|-- tigris
|-- todoStarterApp
|-- todoItems.ts
|-- pages
|-- index.tsx
|-- api
|-- item
|-- [id].ts
|-- items
|-- index.ts
|-- search.ts

Tigris data models and schemas - models/tigrisโ€‹

With Tigris it all starts with the data model! Tigris stores data records as documents. Documents are analogous to JSON objects but Tigris stores them in an optimized binary format. Documents are grouped together in collections.

The to-do list app has a single collection todoItems that stores the to-do items. The first thing you would do is define the schema.

Tigris follows the convention of having the models and schemas stored in the models/tigris directory. Within this directory we have the todoStarterApp directory which is our database name and the file todoItems.ts stores the schema for the collection named todoItems:

import {
} from "@tigrisdata/core/dist/types";

export const COLLECTION_NAME = "todoItems";

export interface TodoItem extends TigrisCollectionType {
id?: number;
text: string;
completed: boolean;

export const TodoItemSchema: TigrisSchema<TodoItem> = {
id: {
type: TigrisDataTypes.INT32,
primary_key: { order: 1, autoGenerate: true },
text: { type: TigrisDataTypes.STRING },
completed: { type: TigrisDataTypes.BOOLEAN },

Connecting to Tigris - lib/tigris.tsโ€‹

This file loads the environment variables that were populated by the Tigris integration and configured the Tigris client. This client is used to manage all the Tigris operations from here on. Also, note how we are caching the client instance so that it can be used for subsequent requests.

import { DB, Tigris, TigrisClientConfig } from "@tigrisdata/core";

const DB_NAME = "todoStarterApp";

if (!process.env.TIGRIS_URI) {
throw new Error("Cannot find TIGRIS_URI environment variable ");

const tigrisUri = process.env.TIGRIS_URI;
const clientConfig: TigrisClientConfig = { serverUrl: tigrisUri };

if (process.env.TIGRIS_CLIENT_ID) {
clientConfig.clientId = process.env.TIGRIS_CLIENT_ID;
if (process.env.TIGRIS_CLIENT_SECRET) {
clientConfig.clientSecret = process.env.TIGRIS_CLIENT_SECRET;

declare global {
// eslint-disable-next-line no-var
var tigrisDb: DB;

let tigrisDb: DB;

if (process.env.NODE_ENV === "development") {
// re-use the same connection in dev
if (!global.tigrisDb) {
const tigrisClient = new Tigris(clientConfig);
global.tigrisDb = tigrisClient.getDatabase(DB_NAME);
tigrisDb = global.tigrisDb;
} else {
const tigrisClient = new Tigris(clientConfig);
tigrisDb = tigrisClient.getDatabase(DB_NAME);

// export to share DB across modules
export default tigrisDb;

Creating the database and collection - scripts/setup.tsโ€‹

The file scripts/setup.ts automatically sets up the database and collection at build time. It looks for the models in the directory models/tigris and creates the databases and collections in an idempotent way instantaneously.


Let's take a look at fetchListItems() in this React component that loads and renders the to-do list items.

// Fetch Todo List
const fetchListItems = () => {

.then((response) => response.json())
.then((data) => {
if (data.result) {
} else {
.catch(() => {

Evidently this React component is only rendering the items returned by /api/items.

Similarly, the addTodoItem(), to add a to-do list item, simply makes a POST request to /api/items.

// Add a new to-do item
const addToDoItem = () => {
if (queryCheckWiggle()) {

fetch("/api/items", {
method: "POST",
body: JSON.stringify({ text: textInput, completed: false }),
}).then(() => {

We will now dive into the API routes to see how these are integrated with Tigris that is powering our application.

Tigris and Serverless Functions

All the API routes are deployed as Serverless Functions. Tigris is serverless itself and natively supports HTTP. This makes it a perfect fit for Serverless Functions.

API routes to find and add itemsโ€‹

All the Next.js API routes are defined under /pages/api/. We have three files: /pages/api/items/index.ts, /pages/api/items/search.ts and /pages/api/item/[id].ts that expose following endpoints:

  • GET /api/items to get an array of to-do items as Array<TodoItem>
  • POST /api/items to add an item to the list
  • GET /api/items/search?q=query to find and return items matching the given query
  • GET /api/item/{id} to fetch an item
  • PUT /api/item/{id} to update the given item
  • DELETE /api/item/[id] to delete an item

Let's look at the /api/items api that supports both GET and POST handlers.

import type { NextApiRequest, NextApiResponse } from 'next'
import { COLLECTION_NAME, TodoItem } from '../../../lib/schema'
import tigrisDb from '../../../lib/tigris'

type Response = {
result?: Array<TodoItem>,
error?: string

// GET /api/items -- gets items from collection
// POST /api/items {ToDoItem} -- inserts a new item to collection
export default async function handler (
req: NextApiRequest,
res: NextApiResponse<Response>
) {
switch (req.method) {
case 'GET':
await handleGet(req, res)
case 'POST':
await handlePost(req, res)
res.setHeader('Allow', ['GET', 'POST'])
res.status(405).end(`Method ${req.method} Not Allowed`)


handleGet() method is fetching and returning items from Tigris collection, let's take a look at its implementation. You will see how easy it is to fetch data from Tigris.

async function handleGet(req: NextApiRequest, res: NextApiResponse<Response>) {
try {
const itemsCollection = tigrisDb.getCollection<TodoItem>(COLLECTION_NAME);
const cursor = itemsCollection.findMany();
const items = await cursor.toArray();
res.status(200).json({ result: items });
} catch (err) {
const error = err as Error;
res.status(500).json({ error: error.message });

The itemsCollection.findMany() function sends a query to Tigris and returns a cursor to fetch results from collection.

Let's look at handlePost() implementation that inserts a TodoItem in collection by using the insertOne() function.

async function handlePost(req: NextApiRequest, res: NextApiResponse<Response>) {
try {
const item = JSON.parse(req.body) as TodoItem;
const itemsCollection = tigrisDb.getCollection<TodoItem>(COLLECTION_NAME);
const inserted = await itemsCollection.insertOne(item);
res.status(200).json({ result: [inserted] });
} catch (err) {
const error = err as Error;
res.status(500).json({ error: error.message });

API route to search itemsโ€‹

Tigris makes it really easy to implement search within your applications by providing an embedded search engine that makes all your data instantly searchable.

Let's take a look at the search handler to see how easy it is to add powerful real-time search functionality. The functions sends a search query to Tigris and fetches the documents that match the query.

Tigris real-time search

Note how you did not have to setup Elasticsearch, or configure search indexes. It was all taken care for you automatically.

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const query = req.query["q"];
if (query === undefined) {
res.status(400).json({ error: "No search query found in request" });
try {
const itemsCollection = tigrisDb.getCollection<TodoItem>(COLLECTION_NAME);
const searchRequest: SearchRequest<TodoItem> = { q: query as string };
const searchResult = await;
const items = new Array<TodoItem>();
for (const hit of searchResult.hits) {
res.status(200).json({ result: items });
} catch (err) {
const error = err as Error;
res.status(500).json({ error: error.message });


In this tutorial, you deployed a to-do list Next.js app that uses Tigris as the backend. You saw all the powerful functionality that Tigris provides, and how easy it is to use it within Serverless Functions.

Tigris is the easiest way to work with data in your Next.js applications. Tigris and Next.js provide developers with the fastest way to build fast, data-rich and highly-responsive applications.

You can find the complete source code for this tutorial GitHub repo, feel free to raise issues or contribute to the project.

Happy learning!

Tigris is the data platform built for Next.js applications! Use it as a scalable, ACID transactional, real-time backend for your serverless applications. Build rich features with dynamic data without worrying about slow database queries or missing indexes. Seamlessly implement search within your applications with its embedded search engine. Connect serverless functions with its event streams to build highly responsive applications that scale automatically.

Sign up for the beta

Get early access and try out Tigris for your next Next.js application. Join our Slack or Discord community to ask any questions you might have.