Farm.js

Getting Started

Create a Farm.js app, understand the files that matter, and run the development server.

Farm requires Node.js 22.13 or newer. This is the first Node 22 release that exposes the built-in node:sqlite module without an experimental command-line flag.

Create an app

Farm keeps the first project small: an app directory, a config file, package metadata, and TypeScript. Vite config and platform config are optional escape hatches, not required setup.

pnpm create @farm.js/app my-app --template basic --typescript
cd my-app
pnpm dev

This command explicitly selects the minimal Basic starter. Use pnpm create, not pnpm add: pnpm resolves the @farm.js/app initializer name to the published @farm.js/create-app package. The scaffolder installs React and all other starter dependencies automatically. Use --skip-install if you only want it to generate the project files.

Right after a release, pnpm can still start the previous initializer: its create cache lasts a day, and pnpm 11's default release-age policy holds back packages published in the last day. Set both for the shell, then run the command again:

export PNPM_CONFIG_DLX_CACHE_MAX_AGE=0
export PNPM_CONFIG_MINIMUM_RELEASE_AGE_EXCLUDE='["@farm.js/*"]'
pnpm create @farm.js/app my-app --template basic --typescript

In PowerShell:

$env:PNPM_CONFIG_DLX_CACHE_MAX_AGE = "0"
$env:PNPM_CONFIG_MINIMUM_RELEASE_AGE_EXCLUDE = '["@farm.js/*"]'
pnpm create @farm.js/app my-app --template basic --typescript

React is the default renderer. The Basic starter can instead use Preact, Solid, Vue, or Svelte:

pnpm create @farm.js/app my-preact-app --template basic --renderer preact --typescript
pnpm create @farm.js/app my-solid-app --template basic --renderer solid --typescript
pnpm create @farm.js/app my-vue-app --template basic --renderer vue --typescript
pnpm create @farm.js/app my-svelte-app --template basic --renderer svelte --typescript

See Renderers before choosing an adapter. Integration starters currently use React because their generated UI and provider packages are React-oriented.

Choose a starter

Use --list-templates to see the same catalog in the terminal. Provider templates include the integration wiring, an app-owned UI feature, .env.example, and a minimal dark home page. Every starter registers the DevTools plugin in farm.config.ts, so the development workspace is available from the first farm dev. Remove devtools() from plugins and drop the @farm.js/devtools dev dependency if you do not want it.

TemplateIncluded capability
basicMinimal Farm.js app
react-compilerExperimental React AOT compiler starter
authFarm.js Auth
better-authBetter Auth
aiAI SDK chat
auth0Auth0
authjsAuth.js with GitHub OAuth
autumnAutumn billing
clerkClerk
jobs-inngestInngest jobs
jobs-triggerTrigger.dev jobs
polarPolar billing
resendResend email
stripeStripe billing
supabaseSupabase Auth
unkeyUnkey API keys
workosWorkOS AuthKit

For example:

pnpm create @farm.js/app stripe-app --template stripe --typescript

The generated README lists the required environment values and links to the provider guide.

To explore Farm's experimental React AOT compiler with the shared dark starter UI:

pnpm create @farm.js/app compiler-app --template react-compiler --typescript

The same project is available as the standalone React Compiler Starter.

What you get

  • File-based routes in src/app.
  • Renderer-owned pages, layouts, loading, error, and not-found boundaries.
  • Route types generated from the route tree.
  • API routes and a generated client for api.users.get style calls.
  • Deployment output powered by Farm config instead of extra root files.

Your first page

The default starter uses React. Preact, Solid, Vue, and Svelte projects should follow their dedicated renderer guide for the equivalent component file.

src/app/page.tsx
import type { PageProps } from "@farm.js/core";

export default function HomePage(_props: PageProps) {
  return <h1>Hello from Farm.js</h1>;
}

Add a layout

Every route can share chrome through layout.tsx. Start with a root layout, then add nested layouts only when a section needs its own navigation or data shell.

src/app/layout.tsx
import type { LayoutProps } from "@farm.js/core";
import "./globals.css";

export default function RootLayout({ children }: LayoutProps) {
  return (
    <main>
      <header>Farm.js</header>
      {children}
    </main>
  );
}

Add an API route

Farm API routes live beside pages and use the same route tree. Define an endpoint, add Zod input when needed, then call it through the generated API client.

src/app/api/hello/route.ts
import { createEndpoint } from "@farm.js/core/api";
import { z } from "zod";

export const POST = createEndpoint(
  {
    method: "POST",
    body: z.object({
      name: z.string().min(1),
    }),
  },
  async ({ body }) => {
    return Response.json({
      message: `Hello ${body.name}`,
    });
  },
);

Create the two callers once in a shared module. Farm generates the route types and path manifest; the endpoint handler is defined only in the route file above.

src/lib/api.ts
import { createApiClients } from "@farm.js/core/client";
import { apiRoutes, type APIRouter } from "./api.generated";

export const { api, apiClient } = createApiClients<APIRouter>({ routes: apiRoutes });

Import api during server requests for local calls, or apiClient in the browser for HTTP calls. See API Client for request context and middleware boundaries.

src/components/hello-button.tsx
"use client";

import { apiClient } from "@/lib/api";

export function HelloButton() {
  return (
    <button
      onClick={async () => {
        const result = await apiClient.hello.post({
          body: { name: "Ada" },
        });

        console.log(result.data?.message);
      }}
    >
      Say hello
    </button>
  );
}

Add authentication

For the default email/password flow, install the optional Farm Auth runtime and enable one config key:

pnpm add @farm.js/auth
export default defineConfig({
  auth: true,
});

The Farm.js Auth Starter includes the complete forms, session UI, protected middleware, local SQLite setup, and production guidance.

Add integrations later

Keep the first app small. When a feature becomes provider-shaped, add it as an integration:

farm add integration stripe --ui
farm add integration unkey

Integrations can contribute typed callers, routes, providers, middleware, database schemas, CLI registry components, config validation, and lifecycle hooks.

Use farm add integration better-auth --ui instead when the application needs to own a Better Auth instance, plugins, adapters, providers, or callbacks. The Better Auth integration guide and Better Auth starter document that explicit path.

Next steps

  • Read Project Structure when you want the compact file layout.
  • Read Renderers when choosing React, Preact, Solid, Vue, or Svelte for the component layer.
  • Read Routing and Layouts when you start nesting pages.
  • Read API Routes and API Client when you need typed server/client calls.
  • Read Integrations when provider features should be packaged instead of copied route-by-route.