diff --git a/packages/docs/src/App.tsx b/packages/docs/src/App.tsx
index d2fe691..1a8255a 100644
--- a/packages/docs/src/App.tsx
+++ b/packages/docs/src/App.tsx
@@ -12,6 +12,7 @@ import DeferAndActivity from "./pages/learn/DeferAndActivity.mdx";
import FileSystemRouting from "./pages/learn/FileSystemRouting.mdx";
import MultipleEntrypoints from "./pages/advanced/MultipleEntrypoints.mdx";
import SSR from "./pages/advanced/SSR.mdx";
+import BuildEntryApi from "./pages/api/BuildEntry.mdx";
import EntryDefinitionApi from "./pages/api/EntryDefinition.mdx";
import FAQ from "./pages/FAQ.mdx";
import GettingStarted from "./pages/GettingStarted.mdx";
@@ -65,6 +66,12 @@ export const routes: RouteDefinition[] = [
path: "/api/defer",
component: {defer(, { name: "DeferApi" })},
}),
+ route({
+ path: "/api/build-entry",
+ component: (
+ {defer(, { name: "BuildEntryApi" })}
+ ),
+ }),
route({
path: "/api/entry-definition",
component: (
diff --git a/packages/docs/src/components/Sidebar/Sidebar.tsx b/packages/docs/src/components/Sidebar/Sidebar.tsx
index 9d1a09d..d6a1787 100644
--- a/packages/docs/src/components/Sidebar/Sidebar.tsx
+++ b/packages/docs/src/components/Sidebar/Sidebar.tsx
@@ -71,6 +71,10 @@ export const navigation: NavSection[] = [
href: "/api/funstack-static",
},
{ label: "defer()", href: "/api/defer" },
+ {
+ label: "BuildEntryFunction",
+ href: "/api/build-entry",
+ },
{
label: "EntryDefinition",
href: "/api/entry-definition",
diff --git a/packages/docs/src/pages/api/BuildEntry.mdx b/packages/docs/src/pages/api/BuildEntry.mdx
new file mode 100644
index 0000000..ca908be
--- /dev/null
+++ b/packages/docs/src/pages/api/BuildEntry.mdx
@@ -0,0 +1,108 @@
+# BuildEntryFunction
+
+The `BuildEntryFunction` type defines a custom build entry point that lets you hook into the production build process. Use it to run additional work before, after, or in parallel with the default build.
+
+## Import
+
+```typescript
+import type { BuildEntryFunction } from "@funstack/static/server";
+```
+
+## Usage
+
+Create a module that default-exports a `BuildEntryFunction`, then reference it via the [`build`](/api/funstack-static#build-optional) option in your Vite config:
+
+```typescript
+// vite.config.ts
+import funstackStatic from "@funstack/static";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ funstackStatic({
+ entries: "./src/entries.tsx",
+ build: "./src/build.ts",
+ }),
+ ],
+});
+```
+
+```typescript
+// src/build.ts
+import type { BuildEntryFunction } from "@funstack/static/server";
+
+export default (async ({ build, outDir }) => {
+ // Run the default build
+ await build();
+ // ... do additional work after the build
+}) satisfies BuildEntryFunction;
+```
+
+## Type Definition
+
+```typescript
+type BuildEntryFunction = (context: BuildEntryContext) => Promise | void;
+
+interface BuildEntryContext {
+ build: () => Promise;
+ outDir: string;
+}
+```
+
+## Context Properties
+
+### build
+
+**Type:** `() => Promise`
+
+Performs the default build flow (rendering entries and writing output files). You must call this function to produce the standard build output. You can run additional work before, after, or in parallel with it.
+
+### outDir
+
+**Type:** `string`
+
+Absolute path to the output directory where built files are written. Use this to write additional files alongside the build output.
+
+## Examples
+
+### Generate a sitemap alongside the build
+
+```typescript
+import { writeFile } from "node:fs/promises";
+import path from "node:path";
+import type { BuildEntryFunction } from "@funstack/static/server";
+
+export default (async ({ build, outDir }) => {
+ const sitemap = generateSitemap(); // your sitemap logic
+
+ await Promise.all([
+ build(),
+ writeFile(path.join(outDir, "sitemap.xml"), sitemap),
+ ]);
+}) satisfies BuildEntryFunction;
+```
+
+By running `build()` and `writeFile()` in parallel with `Promise.all`, the sitemap is generated without adding to the total build time.
+
+### Run work before or after the build
+
+```typescript
+import type { BuildEntryFunction } from "@funstack/static/server";
+
+export default (async ({ build }) => {
+ console.log("Build starting...");
+ await build();
+ console.log("Build complete!");
+}) satisfies BuildEntryFunction;
+```
+
+## Notes
+
+- The build entry module runs in the **RSC environment**, so you have access to Node.js APIs.
+- The `build` option is only used during **production builds** (`vite build`), not in dev mode.
+- If no `build` option is specified, the default build flow runs automatically.
+
+## See Also
+
+- [funstackStatic()](/api/funstack-static) - Plugin configuration (includes the `build` option)
+- [Multiple Entrypoints](/advanced/multiple-entrypoints) - Multi-page static site generation
diff --git a/packages/docs/src/pages/api/FunstackStatic.mdx b/packages/docs/src/pages/api/FunstackStatic.mdx
index 030f9d8..1c695ab 100644
--- a/packages/docs/src/pages/api/FunstackStatic.mdx
+++ b/packages/docs/src/pages/api/FunstackStatic.mdx
@@ -226,6 +226,25 @@ Sentry.init({
**Note:** Errors in the client init module will propagate normally and prevent the app from rendering.
+### build (optional)
+
+**Type:** `string`
+
+Path to a module that customizes the production build process. The module should `export default` a function that receives a `BuildEntryContext` with a `build` function (which performs the default build flow) and an `outDir` string (the output directory path).
+
+This allows you to run additional work before, after, or in parallel with the build — for example, generating a sitemap or other static assets.
+
+Only called during production builds (`vite build`), not in dev mode. The module runs in the RSC environment.
+
+```typescript
+funstackStatic({
+ entries: "./src/entries.tsx",
+ build: "./src/build.ts",
+});
+```
+
+See [BuildEntryFunction](/api/build-entry) for the full type definition and examples.
+
### rscPayloadDir (optional)
**Type:** `string`
@@ -295,5 +314,6 @@ You can use the same Vite commands you would use in a normal Vite project:
- [Getting Started](/getting-started) - Quick start guide
- [Multiple Entrypoints](/advanced/multiple-entrypoints) - Multi-page static site generation
+- [BuildEntryFunction](/api/build-entry) - Custom build entry point
- [defer()](/api/defer) - Deferred rendering for streaming
- [React Server Components](/learn/rsc) - Understanding RSC