ExisJS

Getting Started

In this guide, you'll learn the core fundamentals of ExisJS. To get familiar with the essential building blocks, we'll scaffold a new project, explore the file structure, and create our very first API server.

Language Support

We recommend TypeScript for type-safety and automatic frontend client generation. However, ExisJS fully supports vanilla JavaScript as well. ExisJS leverages esbuild under the hood, meaning you do not need to manually run tsc to start your server.

Prerequisites

Please make sure that Node.js (version >= 20) is installed on your operating system.

Setup

Setting up a new project can be done using our CLI tool. Open your terminal and run the following command to scaffold a new ExisJS project:

~npm create exisjs@latest my-backend

You can also use your package manager of choice:

# npm$ npm create exisjs@latest my-backend
# pnpm$ pnpm create exisjs my-backend
# yarn$ yarn create exisjs my-backend
# bun$ bun create exisjs my-backend
# npx$ npx create-exisjs@latest my-backend

The CLI will prompt you with a few simple questions to customize your project:

Terminal
√ Would you like to use TypeScript? ... No / Yes√ Would you like to use ESLint? ... No / Yes√ Would you like your code inside a `src/` directory? ... No / Yes√ Would you like to customize the import alias (`@/*` by default)? ... No / Yes
Creating a new Exis JS app in my-backend.

The CLI will then create the my-backend directory, install all required dependencies, and populate the project with a conventional base structure.

Core Files

Once the installation is complete, your project directory will look something like this:

exis.config.ts

The root configuration for your application (CORS, Logger, Port).

src/env.tsEnvironment variable validation and typing.
src/http/The file-system routing directory.
server.tsThe strict entry point of your application.
route.tsA basic GET endpoint mapped to the root route.

Your First Server

Let's look at the generated src/http/server.ts. This is the strict entry point of your application, where you can connect to databases and register global plugins.

Functional Server Setup

src/http/server.ts
import { exis } from 'exisjs'
export default exis({  async onStart(app) {    // 1. Connect to your database    // await db.connect()    // 2. Register plugins    // app.plugin(authPlugin)    // The Exis CLI automatically boots the server and file-system routes  },
  async onClose(app) {    // Gracefully close database connections here    // await db.disconnect()  },})

Class-Based (OOP) Server Setup

src/http/server.ts
import { Server } from 'exisjs/decorators'import type { App } from 'exisjs'
@Server()export default class RootServer {  async onStart(app: App) {    // 1. Connect to your database    // await db.connect()    // 2. Register plugins    // app.plugin(authPlugin)    // The Exis CLI automatically boots the server and file-system routes  }
  async onClose(app: App) {    // Gracefully close database connections here    // await db.disconnect()  }}

With ExisJS, the framework automatically handles booting up your server and loading your routes based on the file system. You don't need to manually call app.listen()!

Your First Route

ExisJS uses folder-based routing. Your API structure maps directly to your folders in src/http/.

ExisJS supports two primary styles of writing routes: Functional and OOP (Class-based). You are free to use whichever paradigm fits your team best.

Functional Routing

Functional routing provides a lean, inference-heavy developer experience similar to modern frontend frameworks. Let's declare our first route in src/http/users/route.ts:

src/http/users/route.ts
import { controller, route } from 'exisjs/router'
export default controller({  getUsers: route.get('/', {    handle(req) {      // Return a realistic response structure      return {         data: [          { id: 1, name: 'Alice' },          { id: 2, name: 'Bob' }        ],        total: 2       }    },  }),})

OOP Routing

If you prefer a highly-structured architecture heavily inspired by Angular and NestJS, ExisJS natively provides robust class-based routing using Decorators:

src/http/users/route.ts
import { Controller, Get, Req } from 'exisjs/decorators'import type { Request } from 'exisjs'
@Controller()export default class UsersController {  @Get('/')  getUsers(@Req() req: Request) {    // Return a realistic response structure    return {       data: [        { id: 1, name: 'Alice' },        { id: 2, name: 'Bob' }      ],      total: 2     }  }}

In both examples, because this file is named route.ts and is located in the users folder, it automatically responds to GET /users requests. Whatever you return is automatically serialized to JSON.

Running the Application

Your generated package.json comes pre-configured with the Exis CLI commands. Start the development server with hot-reload by running:

~npm run dev

You will see the server boot up in your terminal:

Terminal
6:18:28 pm [exis] starting development server (v0.1.0)...
 EXIS v0.1.0 ready in 125 ms
 → Local:   http://localhost:4000/ → Network: http://10.39.14.177:4000/ → Environ: development → press h + enter to show help

Open your browser and navigate to http://localhost:4000/ (or the port defined in your .env). You will see:

Response
{  "data": [    {      "id": 1,      "name": "Alice"    },    {      "id": 2,      "name": "Bob"    }  ],  "total": 2}