bknd is dead long live userbase
Run Tests / test (pull_request) Successful in 4m57s

This commit is contained in:
2026-09-27 19:34:06 +05:30
parent 05e0086fcd
commit 0bfcb5ad71
529 changed files with 2385 additions and 2924 deletions
+8 -8
View File
@@ -1,5 +1,5 @@
# bknd starter: Next.js
A minimal Next.js (app router) project with bknd integration.
# userbase starter: Next.js
A minimal Next.js (app router) project with userbase integration.
## Project Structure
@@ -17,16 +17,16 @@ Inside of your Next.js project, you'll see the following folders and files:
│ │ │ └── [[...admin]]
│ │ │ └── page.tsx
│ │ ├── api
│ │ │ └── [[...bknd]]
│ │ │ └── [[...userbase]]
│ │ │ └── route.ts
│ │ └── ...
│ └── bknd.ts
│ └── userbase.ts
└── package.json
```
Here is a quick overview about how to adjust the behavior of `bknd`:
* Initialization of the `bknd` config with helper functions are located at `src/bknd.ts`
* API routes are exposed at `src/api/[[...bknd]]/route.ts`
Here is a quick overview about how to adjust the behavior of `userbase`:
* Initialization of the `userbase` config with helper functions are located at `src/userbase.ts`
* API routes are exposed at `src/api/[[...userbase]]/route.ts`
* Admin UI is rendered at `src/admin/[[...admin]]/page.tsx`
## Commands
@@ -42,4 +42,4 @@ All commands are run from the root of the project, from a terminal:
## Want to learn more?
Feel free to check [our documentation](https://docs.bknd.io/integration/nextjs) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
Feel free to check [our documentation](https://docs.userbase.io/integration/nextjs) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
+10 -10
View File
@@ -1,13 +1,13 @@
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
import { boolean, em, entity, text } from "bknd";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { secureRandomString } from "bknd/utils";
import type { NextjsUserbaseConfig } from "userbase/adapter/nextjs";
import { boolean, em, entity, text } from "userbase";
import { registerLocalMediaAdapter } from "userbase/adapter/node";
import { secureRandomString } from "userbase/utils";
// The local media adapter works well in development, and server based
// deployments. However, on vercel or any other serverless deployments,
// you shouldn't use a filesystem based media adapter.
//
// Additionally, if you run the bknd api on the "edge" runtime,
// Additionally, if you run the userbase api on the "edge" runtime,
// this would not work as well.
//
// For production, it is recommended to uncomment the line below.
@@ -22,7 +22,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd" {
declare module "userbase" {
interface DB extends Database {}
}
@@ -39,7 +39,7 @@ export default {
auth: {
enabled: true,
jwt: {
issuer: "bknd-nextjs-example",
issuer: "userbase-nextjs-example",
secret: secureRandomString(64),
},
cookie: {
@@ -60,15 +60,15 @@ export default {
seed: async (ctx) => {
// create some entries
await ctx.em.mutator("todos").insertMany([
{ title: "Learn bknd", done: true },
{ title: "Learn userbase", done: true },
{ title: "Build something cool", done: false },
]);
// and create a user
await ctx.app.module.auth.createUser({
email: "test@bknd.io",
email: "test@userbase.io",
password: "12345678",
});
},
},
} as const satisfies NextjsBkndConfig;
} as const satisfies NextjsUserbaseConfig;
+1 -1
View File
@@ -10,7 +10,7 @@
"lint": "next lint"
},
"dependencies": {
"bknd": "file:../../app",
"userbase": "file:../../app",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.2.0"
+2 -2
View File
@@ -21,8 +21,8 @@ export default async function Layout({
<div className="ml-3.5 mr-2 font-mono opacity-70">&amp;</div>
<Image
className="dark:invert"
src="/bknd.svg"
alt="bknd logo"
src="/userbase.svg"
alt="userbase logo"
width={183}
height={59}
priority
+1 -1
View File
@@ -1,4 +1,4 @@
import { getApi } from "@/bknd";
import { getApi } from "@/userbase";
import { revalidatePath } from "next/cache";
import { Fragment } from "react";
import { List } from "@/components/List";
+2 -2
View File
@@ -1,4 +1,4 @@
import { getApi } from "@/bknd";
import { getApi } from "@/userbase";
import { Buttons } from "@/components/Buttons";
import { List } from "@/components/List";
import Link from "next/link";
@@ -32,7 +32,7 @@ export default async function SSRPage() {
<p className="text-xs opacity-50">
Sign in with:{" "}
<b>
<code>test@bknd.io</code>
<code>test@userbase.io</code>
</b>{" "}
/{" "}
<b>
@@ -1,9 +1,9 @@
"use client";
import { type BkndAdminProps, Admin } from "bknd/ui";
import { type UserbaseAdminProps, Admin } from "userbase/ui";
import { useEffect, useState } from "react";
export function AdminComponent(props: BkndAdminProps) {
export function AdminComponent(props: UserbaseAdminProps) {
const [ready, setReady] = useState(false);
useEffect(() => {
@@ -1,6 +1,6 @@
import { AdminComponent } from "./Admin";
import { getApi } from "@/bknd";
import "bknd/dist/styles.css";
import { getApi } from "@/userbase";
import "userbase/dist/styles.css";
export default async function AdminPage() {
const api = await getApi({ verify: true });
@@ -1,5 +1,5 @@
import { config } from "@/bknd";
import { serve } from "bknd/adapter/nextjs";
import { config } from "@/userbase";
import { serve } from "userbase/adapter/nextjs";
// since we're using the local media adapter in this example,
// we can't use the edge runtime.
@@ -8,7 +8,7 @@ import { serve } from "bknd/adapter/nextjs";
const handler = serve({
...config,
cleanRequest: {
searchParams: ["bknd"],
searchParams: ["userbase"],
},
});
+2 -2
View File
@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "Create Next & bknd App",
description: "Presented by create next app & bknd",
title: "Create Next & userbase App",
description: "Presented by create next app & userbase",
};
export default function RootLayout({
+3 -3
View File
@@ -1,11 +1,11 @@
import { getApp as getBkndApp } from "bknd/adapter/nextjs";
import { getApp as getUserbaseApp } from "userbase/adapter/nextjs";
import { headers } from "next/headers";
import config from "../bknd.config";
import config from "../userbase.config";
export { config };
export async function getApp() {
return await getBkndApp(config, process.env);
return await getUserbaseApp(config, process.env);
}
export async function getApi(opts?: { verify?: boolean }) {
+1 -1
View File
@@ -19,7 +19,7 @@ export const Buttons = () => (
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://docs.bknd.io/integration/nextjs"
href="https://docs.userbase.io/integration/nextjs"
target="_blank"
rel="noopener noreferrer"
>
+2 -2
View File
@@ -25,12 +25,12 @@ export function Footer() {
</Link>
<Link
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://bknd.io"
href="https://userbase.io"
target="_blank"
rel="noopener noreferrer"
>
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
Go to bknd.io →
Go to userbase.io →
</Link>
</footer>
);