Skip to content

Installing Runnable Mini

Overview

Runnable Mini is a great way to get started with Runnable and a perfectly viable long-term solution. It's easy to set up and doesn't require any additional infrastructure.

Runnable Mini integrates directly with your Next.js or Express application by adding a new authenticated route to your existing router framework at a desired path (e.g. /admin).

Installing Runnable

With npm

bash
npm install -D @runnablejs/express

or with yarn

bash
yarn add -D @runnablejs/express

or with pnpm

bash
pnpm add -D @runnablejs/express

Settings up the required env variables

Environment VariableDescriptionHow to Generate
RUNNABLE_BASE_URLThe base URL for your Runnable instance. This has a default of /admin for Runnable Mini, but should override to be /.Should just provide '/'
RUNNABLE_SECRETA secret key used for encrypting the user's cookie session.Run openssl rand -hex 32 in your terminal
RUNNABLE_AUTH_PROVIDER_FORM(Optional) Set to true to enable login via a form. You must also pass verifyLogin option to installRunnable.Set to true or omit.
RUNNABLE_AUTH_PROVIDER_GOOGLE_CLIENT_IDThe client ID for the Google authentication provider.Generated by Google.
RUNNABLE_AUTH_PROVIDER_GOOGLE_CLIENT_SECRETThe client secret for the Google authentication provider.Generated by Google.
RUNNABLE_AUTH_PROVIDER_GOOGLE_HOSTNAMEThe hostname for the Google authentication provider.E.g. https://admin.company-name.com
RUNNABLE_AUTH_PROVIDER_GOOGLE_HDThe hosted domain for the Google authentication provider. Setting this will limit the email domain allowed to login.Provided by Google.

Setting up with Express

ts
// index.ts
import express from "express";
import { installRunnable } from "@runnablejs/express";
import { getUsers, getTeams, assignTeam } from "./db";
import { auth } from "./auth";

const app = express();

// ... normal express setup

installRunnable(
  app,
  {
    assign_user_to_team: {
      title: "Assign a user to a team",
      execute: async (io) => {
        const users = await getUsers();
        const user = await io.select.dropdown({
          label: "Select a user",
          data: users,
          getLabel: (user) => user.name,
          getValue: (user) => user.id,
        });

        const teams = await getTeams();
        const team = await io.select.table({
          label: "Select a team",
          data: teams,
          headers: ["Name", "Team size"],
          initialSelection: user.teamId,
          getValue: (team) => team.id,
          getRow: (team) => [team.name, team.members.length],
        });

        await assignTeam(user.id, team.id);
      },
    },
  },
  { auth: auth }
);

app.listen(3000);

Setting up with Next.js

Create the providers for the RunnableWorkflows and RunnableAppContext.

ts
// actions.provider.ts

import { FactoryProvider, Provider } from "@nestjs/common";
import { RunnableWorkflows, RunnableAppContext } from "@runnablejs/express";
import { DatabaseService } from "./db.service";

export const ActionsProvider: FactoryProvider<RunnableWorkflows> = {
  provide: "RUNNABLE_ACTIONS",
  inject: [DatabaseService],
  useFactory: (database: DatabaseService) => ({
    assign_user_to_team: {
      // ...
    },
    create_user: {
      // ...
    },
  }),
};

export const RunnableAppContextProvider: Provider<RunnableAppContext> = {
  provide: "RUNNABLE_CONTEXT",
  useFactory: (authService: AuthService) => ({
    auth: {
      verifyLogin: (opts) => authService.verifyLogin(opts),
    },
  }),
};

Create the module for the Actions and ActionsContext.

ts
// actions.module.ts
import { Module } from "@nestjs/common";
import {
  ActionsProvider,
  RunnableAppContextProvider,
} from "./actions.provider";
import { AppController } from "./app.controller";

@Module({
  providers: [ActionsProvider, ActionsActionsContextProvider],
})
export class ActionsModule {}

Start your Next.js application with Actions.

ts
// main.ts
import { installRunnable } from "@runnablejs/express";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Runnable
  const actions = app.get("RUNNABLE_ACTIONS");
  const context = app.get("RUNNABLE_CONTEXT");
  installRunnable(app, actions, context);

  await app.listen(3000);
}
bootstrap();

Released under the MIT License.