Docs/Getting Started/Application Modules

Getting Started

Application Modules

Application Modules — Getting Started documentation for BCP Framework.

Last updated: 2026-08-29T17:13:55

Application Modules

BCP applications can import project files through the project-root @/ alias.

TypeScript
import {
    db,
} from "@/lib/database";

The generated tsconfig.json maps @/* to the project root. BCP also installs a Node.js resolver during development so the same alias works in SSR, loader and API route modules. Production builds resolve the alias through the application bundler.

Client modules

A page or shared module that uses React client hooks must begin with the "use client" directive.

TypeScript
"use client";

import {
    useEffect,
    useState,
} from "react";

export default function UsersPage() {
    const [users, setUsers] =
        useState([]);

    useEffect(
        () => {
            void fetch("/api/users")
                .then(
                    (response) =>
                        response.json()
                )
                .then(
                    setUsers
                );
        },
        []
    );

    return (
        <pre>
            {JSON.stringify(users, null, 2)}
        </pre>
    );
}

BCP checks client-reachable page/layout module graphs at development startup and production build time. Using React client hooks without "use client" causes a boundary error.

Client island files (*.island.ts and *.island.tsx) are already explicit client entry points and keep their existing island semantics.

Server-only modules

Use bcp/server-only in modules that contain database clients, secrets, filesystem access, or other code that must never enter a browser bundle.

TypeScript
import "bcp/server-only";

import mysql from "mysql2/promise";

export const db =
    mysql.createPool(
        process.env.DATABASE_URL ??
        ""
    );

Database helpers generated by create-bcp-app include this marker automatically.

Do not import a server-only module directly from a page or client component:

TypeScript
// Not allowed in a page/client graph
import {
    db,
} from "@/lib/database";

For browser-driven data operations, put the database operation behind an API route:

TypeScript
// app/api/users/route.ts
import {
    db,
} from "@/lib/database";

export async function GET() {
    const [rows] =
        await db.query(
            "SELECT * FROM users"
        );

    return Response.json({
        data: rows,
    });
}

Then call the API from the client:

TypeScript
const response =
    await fetch(
        "/api/users"
    );

const result =
    await response.json();

Server data loaders

BCP 0.1.9 adds a server-only page data path. A loader.ts next to page.tsx is not part of the hydrated page graph and may import server-only database helpers directly.

text
app/users/
├─ loader.ts
└─ page.tsx
TypeScript
// app/users/loader.ts
import {
    db,
} from "@/lib/database";

export async function loader() {
    const [rows] =
        await db.query(
            "SELECT id, name FROM users"
        );

    return {
        users: rows,
    };
}

The page consumes only the serializable result:

TypeScript
"use client";

import {
    useLoaderData,
} from "bcp";

export default function UsersPage() {
    const data =
        useLoaderData<{
            users: Array<{
                id: number;
                name: string;
            }>;
        }>();

    return (
        <pre>
            {JSON.stringify(
                data.users,
                null,
                2
            )}
        </pre>
    );
}

The loader itself stays server-only; only its validated JSON-safe result is serialized for hydration. See Server Data Loaders for request context, authentication, redirects and cache behavior.

Current boundary model

BCP 0.1.x is not a React Server Components implementation. Pages and layouts can participate in browser hydration, so server-only dependencies must remain behind explicit server execution paths: API routes, route-level server data loaders, middleware, or other framework server runtimes. The boundary checks are designed to prevent accidental database or secret-bearing code from entering client bundles.