How to get started with the TERN stack
Tags: react, typescript, node, serverless
Published: 2023-04-27 22:37:26


In this post, I'll introduce you to the TERN stack, explain why you should consider adopting it or migrating your MERN stack application over to TERN, and show how you can get started using hot-off-a-git-push 🔥 TERN GitHub template.

## What is the TERN stack?
The TERN stack is an evolution of the MERN stack, replacing MongoDB with Tigris.

The TERN stack is made up of:

- [**T**igris](https://www.tigrisdata.com?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to): An open source Serverless NoSQL Database & Search platform
- [**E**xpress.js](https://expressjs.com/): Fast, unopinionated, minimalist web framework for Node.js
- [**R**eact](https://react.dev/): The library for web and native user interfaces
- [**N**ode.js](https://nodejs.org): an open-source, cross-platform JavaScript runtime environment

![The TERN stack architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yachzr909ubqojb3vt4k.png)

The TERN stack allows you to build your web apps end-to-end with JavaScript or TypeScript.

## Why use the TERN stack?

There is a proliferation of new fullstack all-in-one frameworks such as Next.js, Nuxt.js, SvelteKit, Redwood.js, Blitz.js, Astro, Gatsby... However, there is still some value in choosing to go with a more loosely coupled architecture:

• Better flexibility, maintainability, and scalability: components can be added, removed, or modified with minimal impact on other parts of the system.
• Increased reusability: System components can be reused across different systems or applications, reducing the time and effort required to develop new systems.
• Better fault tolerance: If one component fails, it is less likely to affect the entire system. The system can continue to operate with minimal disruption while the failed component is replaced or repaired.
• Simplified testing: It is easier to isolate and test individual parts of the system.
• Reduced dependencies: Fewer dependencies between components, which can reduce the complexity and cost of development and maintenance. And [dependency hell](https://www.explainxkcd.com/wiki/index.php/1579:_Tech_Loops).
• Improved performance: In some cases, loosely coupled architectures can improve performance by allowing components to operate independently and in parallel.

And you get this by building a loosely coupled front-end and back-end with the TERN stack.


[![Tigris Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wuf4p9uowjzedorh7yd.png)](https://www.tigrsdata.com?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to)

The **T** in TERN stands for Tigris, an open source NoSQL database and search platform. So, the benefits that Tigris offers are also direct benefits in TERN:

- Takes a code-first approach to [database schema modeling](https://www.tigrisdata.com/docs/sdkstools/typescript/database/datamodel/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to) and [search index modeling](https://www.tigrisdata.com/docs/sdkstools/typescript/search/datamodel/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to).
- Supports [database branching](https://www.tigrisdata.com/docs/sdkstools/typescript/database/branching/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to) to fit into your development workflow.
- Supports [ACID transactions without caveats](https://www.tigrisdata.com/blog/transaction-internals-tigris/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to).
- Is a unified developer data platform offering Database AND Search in the same platform. There's no requirement to run a database and search service in parallel.
- Has been built with a modern cloud-native architecture, meaning the running costs are lower than MongoDB, DynamoDB etc.
- Tigris Cloud is fully managed, removing any need for manual cluster provisioning and shard management that are apparent in solutions such as MongoDB Atlas.

If you're a JavaScript or TypeScript developer/engineer/hacker, then you get all of the above and get to code in the programming language you love ❤️

## TERN stack pre-requisites

A computer, Git and Node.js installed on it, 10 minutes of your time... That's about it!

## Getting started with a TERN stack application (and TypeScript)

You can scaffold out your own TERN stack application using your favorite combination of CRA (Create React App), Vite templates, Express.js app generator etc. etc.

However, I want you to be able to get hands-on and building as quickly as possible. So, I created a [TERN stack GitHub template](https://github.com/tigrisdata-community/tern-stack-template). The TERN stack template is made up of:

- A client created using the [Vite React TypeScript template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts)
- An Express.js server carefully hand-crafted by yours truly. In TypeScript!
- A shared package so that client and server can benefit from a shared interface definition for client-server communication. TypeScript.
- All this packaged up in a **monorepo** (sounds way more monolithic than it is; it's just three packages using [NPM workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces)). Not TypeScript 😞 `package.json` is JSON.

So, let's get started.

### The TERN stack GitHub template

Head to the [TERN stack GitHub template](https://github.com/tigrisdata-community/tern-stack-template) and either **Use this template** -> **Create a new repository** -> Choose a name for your repo e.g. `tern-app` -> and **Clone** your repo locally.

{% youtube https://youtu.be/b0jD8K5_WqQ %}

### Install dependencies for apps and packages

Now that you have the code cloned locally (on that computer I flagged as being important earlier), `cd` into the application directory and install the dependencies for the monorepo/workspace.

```sh
cd tern-app
npm i -ws --include-workspace-root
```

This installs the dependencies for React application, Express.js application, shared package, and the root workspace (the top-level `package.json`).

### Create a Tigris Project

The TERN stack template provides a command to create a Tigris project from the command line. It makes use of the [Tigris CLI](https://github.com/tigrisdata/tigris-cli) and will take you through the flow of authorizing itself with Tigris Cloud. This means either logging into your existing Tigris Cloud account or creating a new account.

Run the following NPM script:

```sh
npm run tigris:init --project=tern-app
```

Once you have authorized the Tigris CLI it will create a new `.env.local` file in `apps/server`, containing Tigris project configuration. This will be loaded into the Express.js app and used with the [Tigris TypeScript SDK](https://www.tigrisdata.com/docs/sdkstools/typescript/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to).

### Run the React client and the Express.js server

Start the React client using the following command:

```sh
npm run dev -w=@tern-app/client
```

And start the Express.js server with the following command:

```
npm run dev -w=@tern-app/server
```

You can now launch your browser and head to `http://localhost:3000` to see your TERN app in action.

{% youtube https://youtu.be/Cf6sJuX4o0U %}

Clicking in the page will add rotating stars to the UI, their location is persisted in an `events` collection within Tigris Database via the Express.js server. Clicking on an existing star removes it, and the details of that event are removed from the Tigris Database `events` collection.

## Brief TERN template code walkthrough

```
.
├── apps
│   ├── client
│   │   ├── index.html
│   │   └── src
│   │       ├── App.css
│   │       ├── App.tsx
│   │       ├── index.css
│   │       ├── lib
│   │       │   └── analytics.ts
│   │       └── main.tsx
│   │ 
│   └── server
│       ├── scripts
│       │   └── setup.ts
│       ├── src
│       │   ├── db
│       │   │   └── models
│       │   │       └── event.ts
│       │   │   
│       │   ├── index.ts
│       │   └── utils
│       │       └── validateInput.ts
│       └── .env.local
└── packages
    └── shared
        └── src
            ├── event.ts
            └── index.ts
```

### `apps/client`

The React application, powered by Vite. The main files in this template are:
- `src/App.tsx`: contains the UI-related functionality. In the default template example, this file manages tracking clicks and displaying clicks. It uses `src/lib/analytics.ts` to interact with the Express.js server API endpoints.
- `src/lib/analytics.ts` provides a simple wrapper around `fetch` requests made to API endpoints defined by the Express.js server.

### `apps/server`

The Express.js application.
* `script/setup.ts`: A file that is run before most other scripts to ensure the Tigris data models defined in TypeScript are in sync with that is in Tigris.
* `src/db/models/event.ts`: Defines the [Tigris data models](https://www.tigrisdata.com/docs/sdkstools/typescript/database/datamodel/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to) that represent the application's database schema.
* `src/index.ts`: The main entry point for the Express.js application. Defines the API endpoints and makes use of the [Tigris TypeScript SDK](https://www.tigrisdata.com/docs/sdkstools/typescript/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to) to insert and delete documents into the NoSQL database.
* `src/utils/validateInput.ts`: an Express.js middleware wrapper that makes use of [zod](https://zod.dev/) to validate request body payloads to the API endpoints.
* `.env.local`: Contains environmental variables used within the application. This was created via the `tigris:init` script and contains the Tigris project configuration.

### `packages/shared`

- `src/event.ts`: Defines interfaces that are used both within the client and server. This is a great step towards ensuring that the loose coupling between client and server doesn't also result in API requests and responses mismatching. I personally think this is a really powerful. It's also great for refactoring code between the client and server.

Dive into the codebase, make updates, and find out more.

## Get involved

I'd love to hear your feedback on the [TERN stack](https://www.tigrisdata.com/blog/tern-stack/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to), the [TERN stack template](https://github.com/tigrisdata-community/tern-stack-template), and [Tigris](https://www.tigrisdata.com?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to).

This is v0.1.0 of the TERN stack template, and there are [a few known issues](https://github.com/tigrisdata-community/tern-stack-template/issues) if you'd like to help out.

Give me [(@leggetter) a shout on Twitter](https://twitter.com/leggetter).

[Join the Tigris Discord](https://www.tigrisdata.com/discord/?utm_source=dev-to&utm_medium=blog&utm_campaign=tern-stack&utm_id=tern-stack-dev-to) to share your feedback, get help, or generally hang out.