Rama Nath Thakur

Dec 02, 2025 • 5 min read

Kairo - Workflow Automation Platform

Second chapter of me trying to document my coding journey for my own help ( and hopefully others ) in future.

Kairo - Workflow Automation Platform

Little context in me - I’m trying to build a workflow automation platform similar to n8n, and I’m following Code with Antonio for this project. I’ve done a few projects in the past, and they’ve been a good learning curve that kept my curiosity for development alive. But I’ve always had one issue: I get stuck in tutorial hell, and the actual increase is marginal.

I’ve figured out a way around this. My flow now is to watch tutorials, code once a topic is finished, get help if I’m stuck, then revisit everything at the end of the day and write a blog about it. I write the blog because explaining concepts in simple terms helps me remember them for longer. The plan is to rebuild everything using only my blogs during my summer break and update how this experiment turns out.


High level architecture of the project till now:

  • I’ve connected Prisma with NeonDB as my Postgres provider.

  • Better Auth handles authentication and stores user information in my own database, which gives me full control.

  • tRPC is running in the background. I plan to use it later for more efficient route protection. It feels similar to how RSC behaves, though I’m not fully sure yet. Will update.

    1. Connecting Prisma with NeonDB :

This part is simple if you follow the docs. In short, install Prisma using npm, initialize Prisma, then create a NeonDB account and copy the connection string. It usually looks like this:


# Connect to Neon with pooling (used by Prisma Client via the adapter).
DATABASE_URL=postgres://daniel:<password>@ep-mute-rain-952417-pooler.us-east-2.aws.neon.tech/neondb?sslmode=require

# Direct connection to the database used by the Prisma CLI.
DIRECT_URL="postgres://daniel:<password>@ep-mute-rain-952417.us-east-2.aws.neon.tech/neondb"

The -pooler part tells Neon whether to use connection pooling. Pooling is for serverless workloads where Neon automatically manages connections. Direct connections are recommended for long-running apps that need persistent connections. You can swap between the two by adding or removing the -pooler suffix.

After putting the connection strings in .env, configure Prisma:

import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'

export default defineConfig({
 schema: 'prisma/schema.prisma',
 datasource: {
 url: env('DIRECT_URL'),
 },
})


Now, we can use Prisma commands like npx prisma studio to directly talk with the db, visualize and see/perform operations on db.

Prisma x Neon DB Documentation

2. BetterAuth Setup

Choosing Better Auth was a hard decision because I’ve been comfortable with Clerk for a long time, and it felt easier at the start since we don’t have to manually adjust or tweak everything. But that’s also the beauty of Better Auth. We get full manual control, which puts us in the front seat to drive the entire logic and features and have an in-house auth setup. Kinda cool 😉

The setup is easy compared to others. We install the Better Auth client, set the environment variables in .env (which we can grab from their website), create a Better Auth instance, and configure our database or ORM. In this case, I’m using Prisma as the ORM, so my auth.ts file (where we write the auth logic) looks like this:

import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
// If your Prisma file is located elsewhere, you can change the path
import { PrismaClient } from "@/generated/prisma/client";

const prisma = new PrismaClient();
export const auth = betterAuth({
 database: prismaAdapter(prisma, {
 provider: "postgresql", // or "mysql", "sqlite", ...etc
 }),
});

We also need to create and migrate the Prisma tables to generate everything required for authentication. After that, we mount the handler for Next.js so Better Auth can work correctly with our tech stack and its nuances.

We then create an auth client to have a client-side instance for the user-facing parts of the app. It looks like this:

import { createAuthClient } from "better-auth/react"
export const authClient = createAuthClient({
 /** The base URL of the server (optional if you're using the same domain) */
 baseURL: "http://localhost:3000"
})

BetterAuth Documentation

3. Some Nuances that were taken care of

This speific code block is the one I use the most. It checks for user sessions and performs actions based on that.

import { headers } from "next/headers"
import { auth } from "./auth"
import { redirect } from "next/navigation";

export const requireAuth = async () => {
 const session = await auth.api.getSession({
 headers: await headers(),
 })

 if (!session) {
 redirect("/login");
 }
}
export const requireUnauth = async () => {
 const session = await auth.api.getSession({
 headers: await headers(),
 })

 if (session) {
 redirect("/");
 }
}

requireAuth() is for pages that require the user to be logged in. We check for an active session in the Next.js headers, and if none exists, we redirect the user to the /login page, which is the entry point for unauthenticated users.

requireUnauth() is the opposite. It’s for pages where the user needs to be logged out, such as /login and /register for sign-in and sign-up.

More to focus on:

• tRPC and understanding how and why it’s used or preferred.
• Inngest. The setup is done, but I still need to explore it. You can follow the docs, and everything is straightforward up to the installation part.


I think that's all i have for today, i guess it is a little repetetive kinda blog and not as detailed as i would like but we only had installation part for discussion today, which comes plainly out of docs and i would like everyone to atleast once go through it all, it helps in future when we try to setup everything on our own.

Sayonara 🤗

Join Rama Nath on Peerlist!

Join amazing folks like Rama Nath and thousands of other builders on Peerlist.

peerlist.io/

It’s available... this username is available! 😃

Claim your username before it's too late!

This username is already taken, you’re a little late.😐

0

0

0