Front-End Frameworks Used in Karakeep: Next.js 16, React Native, and Expo

Karakeep uses Next.js 16 for the web application, React Native with Expo for mobile devices, and React 19 for the browser extension, all unified by a shared React component library built on Tailwind CSS, Shadcn UI, and Radix UI primitives.

The open-source bookmarking application Karakeep (formerly Hoarder) maintains a consistent React-centric architecture across all client platforms. Understanding the front-end frameworks used in Karakeep reveals how the project delivers a unified experience across web, mobile, and browser extension environments while maximizing code reuse through the @karakeep/shared-react package.

Web Application: Next.js 16 with React 19

The Karakeep web client resides in apps/web/ and runs on Next.js 16, a React-based server-rendered framework. According to apps/web/package.json, the project declares next, react, and react-dom as core dependencies, confirming the Next.js architecture alongside React 19.

The implementation uses the Pages Router convention, as evidenced by file paths like apps/web/pages/index.tsx. The stack includes Tailwind CSS for styling, Shadcn UI for pre-built components, and Radix UI for accessible primitives. Data fetching relies on a tRPC client paired with React Query for type-safe server communication.

// apps/web/pages/index.tsx
import { NextPage } from "next";
import Head from "next/head";

const Home: NextPage = () => (
  <main className="flex min-h-screen flex-col items-center justify-center bg-gray-50">
    <Head>
      <title>Karakeep – Read‑it‑later</title>
    </Head>
    <h1 className="text-4xl font-bold">Welcome to Karakeep</h1>
    <p className="mt-4 text-lg">Your bookmarks, everywhere.</p>
  </main>
);

export default Home;

This entry point demonstrates the Next.js Pages Router pattern, React component structure, and Tailwind utility classes (className) that define the styling system.

Mobile Application: React Native with Expo

For iOS and Android, Karakeep leverages React Native running inside the Expo ecosystem. The apps/mobile/package.json manifest lists react-native, expo, and expo-router as primary dependencies, establishing the standard React Native + Expo stack.

The mobile app uses NativeWind to bring Tailwind CSS classes to React Native components, allowing shared styling logic with the web platform. Navigation relies on Expo Router using file-based routing in apps/mobile/app/, while UI primitives come from Radix UI via the @rn-primitives package.

// apps/mobile/app/(home)/index.tsx
import { Text, View } from "react-native";
import { Link } from "expo-router";
import { cn } from "@karakeep/shared-react/utils"; // Tailwind merge helper

export default function HomeScreen() {
  return (
    <View className={cn("flex-1 items-center justify-center bg-white")}>
      <Text className="text-2xl font-bold">Karakeep Mobile</Text>
      <Link href="/bookmarks" className="mt-4 text-blue-600">
        View Bookmarks
      </Link>
    </View>
  );
}

This screen uses React Native core components (View, Text), Expo Router's Link component for navigation, and the cn utility from the shared package to handle Tailwind class merging via NativeWind.

Browser Extension: React 19 with Vite

The browser extension located in apps/browser-extension/ uses React 19 bundled with Vite (or webpack). Unlike the web app, it does not use Next.js, but it imports the same Shadcn UI and Radix UI components from the shared library, ensuring visual consistency with the main web application.

Shared UI Architecture: Tailwind, Shadcn UI, and Radix

Both web and mobile applications import components from @karakeep/shared-react, a centralized package that houses the design system. This package integrates Tailwind CSS (via tailwind-merge), Shadcn UI components, and Radix UI primitives.

The apps/web/components.json file confirms the Shadcn UI configuration schema, while packages/shared-react/components/ui/button.tsx demonstrates how base components wrap Radix primitives with Tailwind styling.

// packages/shared-react/components/ui/button.tsx
import * as React from "react";
import * as ButtonPrimitive from "@radix-ui/react-button";
import { cn } from "@/utils";

export const Button = React.forwardRef<
  React.ElementRef<typeof ButtonPrimitive.Root>,
  React.ComponentPropsWithoutRef<typeof ButtonPrimitive.Root>
>(({ className, ...props }, ref) => (
  <ButtonPrimitive.Root
    ref={ref}
    className={cn("inline-flex items-center rounded-md px-4 py-2", className)}
    {...props}
  />
));
Button.displayName = "Button";

Both the Next.js web app and React Native mobile app consume this component, gaining a consistent look-and-feel across platforms while the implementation details remain framework-agnostic.

Summary

  • Next.js 16 powers the web application in apps/web/, using React 19 and the Pages Router structure.
  • React Native with Expo drives the mobile experience in apps/mobile/, utilizing Expo Router for navigation.
  • React 19 runs the browser extension via Vite, sharing UI components with the web platform.
  • A shared @karakeep/shared-react package provides Tailwind CSS, Shadcn UI, and Radix UI components across all front-ends.
  • NativeWind enables Tailwind-style utility classes in the React Native mobile environment.

Frequently Asked Questions

Does Karakeep use Next.js App Router or Pages Router?

Based on the source code structure, Karakeep uses the Pages Router convention, as evidenced by the apps/web/pages/ directory structure. The example entry point at apps/web/pages/index.tsx follows the traditional Next.js pages pattern rather than the newer app directory structure.

How does Karakeep share UI components between web and mobile platforms?

Karakeep maintains a shared component library in packages/shared-react/ that exports UI primitives built on React and Tailwind CSS. Both the Next.js web app and the React Native mobile app import these components, with the mobile layer using NativeWind to interpret Tailwind classes in the native environment.

What is the role of Expo in the Karakeep mobile app?

Expo provides the build tooling, development environment, and runtime services for the React Native application. Specifically, expo-router handles navigation using file-based routing in apps/mobile/app/, while the Expo SDK supplies native modules for device capabilities. The apps/mobile/package.json confirms this dependency stack.

Is the browser extension built with Next.js?

No, the browser extension uses React 19 directly, bundled with Vite or webpack rather than Next.js. However, it imports the same Shadcn UI and Radix UI components from the shared package, ensuring UI consistency with the main web application without the overhead of the Next.js framework.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →