Point0by 1gr14
  • Меню
    • GitHub
    • Блог
  • Introduction
    • Overview
    • Getting Started
    • Full Overview
    • Benchmarks
    • Points
  • Points
    • Page
    • Layout
    • Component
    • Provider
    • Mountable
    • Query
    • Infinite Query
    • Mutation
    • Action
    • Root
    • Base
    • Plugin
  • Methods
    • Validation
    • Loader
    • Context
    • Middleware
    • Loading & error
    • .with
    • Mapper
    • Transformer
    • Stage Methods
  • Core
    • Navigation
    • SSR
    • RSC
    • Request
    • Response
    • Error handling
    • Env
    • Head
    • MDX
    • Assets
    • File upload
    • OpenAPI
    • Query client
    • Events
    • Infer
  • Engine
    • Engine Config
    • Engine Runtime
    • CLI
    • Dev
    • Build
    • Compiler
    • Generator
    • Project MCP
    • Docs MCP
    • Importer
    • Public dir
    • Testing
    • Deploy
    • Bun or Vite
  • Extra
    • SsrStore
    • CookieStore
    • Basic Auth
    • CORS
    • Cache-Control
    • Compress
  • Examples
    • Basic
    • Vite
    • Better Auth
    • Capacitor
    • Expo
  • 1gr14
    • Главная
    • Start0
    • Поддержать
    • Обучение
    • Группа
    • Блог
    • Автор
  • Сообщество
    • Discord
    • Telegram
  • Опенсорс
    • Point0
    • Route0
    • Error0
    • Flat
  • Аккаунт
    • Войти
    • Регистрация
Point0by 1gr14
Создаю опенсорс во славу Господа Иисуса Христа ☦️
С любовью ко всем разработчикам на свете ❤️
Условия использованияПолитика конфиденциальностиСергей Дмитриев 2026 😎

Getting Started

  • Раздел: Introduction

On this page

  1. The scaffolder
  2. Bun is required
  3. TypeScript 6 or 7 — both work
  4. Bun or Vite — pick at scaffold time
  5. Everyday commands
  6. No leaked dev servers
  7. Manual setup
  8. The package.json scripts
  9. src/engine.ts — the engine config
  10. The four entry files
  11. What else the scaffolder gives you
  12. Reference
  13. Scripts the CLI backs
  14. Entry files

One command is the whole setup. It scaffolds a complete app — SSR, Prisma + SQLite, Tailwind, type-safe routing — installs dependencies, and runs codegen:

bun create point0-app@latest
# prompts for a name and a bundler (Bun or Vite), installs deps, runs setup
cd my-app
bun run dev # http://localhost:3001 (client) + http://localhost:3000 (server)

That's it — the app is running. You need Bun; the scaffolder offers to install it if it's missing.

The home page ships a small playground: an Idea Prisma model, a query that lists the rows, and a mutation with a form that adds one — setup seeds a few ideas, so there's something to poke at right away.

The rest of the page is optional depth: the scaffolder, the commands you'll run every day, and manual setup — every file the scaffolder writes, for when you'd rather wire the app by hand.

The scaffolder

bun create point0-app resolves to the create-point0-app package by Bun's create-<x> convention. With no arguments it prompts interactively: project name, bundler (Bun or Vite, default Bun), install now (default yes), and override (asked only when the target directory is non-empty). Pass a name and flags to skip the prompts:

bun create point0-app@latest my-app          # name as a positional argument
bun create point0-app@latest my-app --vite   # use Vite for the client bundle
bun create point0-app@latest my-app --no-install   # scaffold only, don't install
bun create point0-app@latest my-app -I       # non-interactive, take all defaults

It scaffolds into <cwd>/<name>. If that directory already exists and is not empty, the run stops unless you pass --override (or confirm the prompt).

FlagDefaultWhat it does
[name]my-appDirectory name for the new app
--vite / --no-vite--no-vite (Bun)Bundle the client with Vite instead of Bun
--install / --no-install--installRun bun install + bun run setup after scaffolding
-O, --overrideoffAllow writing into a non-empty target directory
-I, --no-interactiveoffSkip every prompt and use the defaults above

Bun is required

The scaffolder checks for Bun first. With -I and no Bun on PATH, it errors out (Bun is required but was not found in PATH). Interactively, it offers to install Bun globally with npm install -g bun before continuing.

bun create point0-app is the only supported entry point — there's no npx / pnpm dlx / yarn create equivalent. Those would resolve the create-point0-app bin, but both the scaffolder and the app it writes run on Bun, so they'd dead-end the moment you tried to use the result.

TypeScript 6 or 7 — both work

Point0 never loads TypeScript. dev, build and generate don't touch the compiler API: the Point0 compiler parses your code with Babel and reads the paths aliases out of tsconfig.json itself. So the TypeScript in your project is yours alone — 6, 7, or none at all, the framework behaves identically.

The scaffold pins TypeScript 7, and bun run types runs its tsc.

Staying on 6 is a normal choice, and one tool makes it the right one: typescript-eslint's type-aware linting doesn't run on TypeScript 7 — 7.0 ships no compiler API, and typescript-eslint needs one. Support is waiting on the stable API in 7.1. If you lint with projectService or project, keep "typescript": "^6.0.3" and add the new compiler under a second name:

{
  "devDependencies": {
    "typescript": "^6.0.3",
    "@typescript/native": "npm:typescript@^7.0.2"
  }
}

tsc then resolves to TypeScript 7 while import 'typescript' still hands typescript-eslint the API it needs. This is exactly how the Point0 repo itself is set up. Don't alias the typescript name to @typescript/typescript6 — under Bun the alias resolves back into itself and you end up with an empty API.

Bun or Vite — pick at scaffold time

The --vite choice changes which files you get:

  • Bun (default) — Bun bundles the client; Tailwind comes from bun-plugin-tailwind, declared as bunPlugins in engine.ts. No vite.config.ts.
  • Vite — Vite bundles the client via a viteConfig block in engine.ts and a vite.config.ts; CSS is linked from index.html; preload.ts gets preventLoadBunPlugins: true.

You can't have both — engine.ts carries viteConfig or bunPlugins, never both. The trade-offs are in bun-vs-vite; the Vite walkthrough is vite.

Everyday commands

Four scripts you'll live in:

bun run dev      # point0 dev --hot — dev server + client, server hot reload
bun run setup    # migrate the SQLite DB, generate Prisma + point0 code, seed
bun run build    # point0 build → dist/
bun run start    # NODE_ENV=production bun run ./dist/server/index.server.js

With --install (the default) the scaffolder already ran bun install and bun run setup, so bun run dev works right away. Run the chain yourself after --no-install, a fresh clone, or a database reset:

bun install
bun run setup
bun run dev

bun run setup is the important one. src/generated/ (the Prisma client and point0's points / routes / assets) is gitignored — setup produces it. Without it, typecheck fails and the app won't run.

Why setup, not prepare? A prepare script runs on every bun install — which breaks installs where no database exists yet (CI, a monorepo). So the codegen + DB step is named setup and run explicitly, not on install.

There is no point0 start command — production runs the built server entry directly; see deploy. point0 dev and point0 build are thin wrappers over engine.dev() / engine.build() — full flag lists in cli, dev, and build. --hot hot-swaps edited points without restarting the server; it's marked experimental in the CLI help.

No leaked dev servers

Every process in the dev tree dies with whatever launched it: the point0 CLI spawns each dev child with Bun's --no-orphans flag (inherited by nested bun processes), and the scaffolded bunfig.toml sets [run] noOrphans = true so the bun run dev wrapper itself dies with the terminal. Close the terminal and the dev server (and all its children) exits with it — no orphaned servers holding ports.

--no-orphans landed in Bun 1.3.14, so that's the floor — the generated package.json declares it as "engines": { "bun": ">=1.3.14" }. On an older Bun the dev server still runs, but it can leak orphaned processes that keep holding ports; upgrade with bun upgrade.

Manual setup

Everything below is what the scaffolder writes for you — skip this section if you used bun create point0-app. Point0 is just a set of packages, so you can assemble an app from a handful of files. Each one is cited from the template so you can copy it.

The package.json scripts

The four core scripts map directly to the point0 CLI:

{
  "scripts": {
    "dev": "point0 dev --hot", //   dev server + clients, server hot reload
    "generate": "point0 generate", // write src/generated/point0/* from your points
    "build": "point0 build", //     build server + clients into dist/
    "start": "cross-env NODE_ENV=production bun run ./dist/server/index.server.js",
  },
}

The supporting scripts complete the setup chain — Prisma helpers, a seed, and typecheck:

{
  "scripts": {
    "setup": "bun run prisma:migrate:deploy && bun run prisma:generate && point0 generate && bun run seed",
    "seed": "cross-env NODE_ENV=development bun --preload ./src/preload.ts ./src/lib/seed.ts",
    "prisma:generate": "cross-env NODE_ENV=development prisma generate",
    "prisma:migrate:deploy": "cross-env NODE_ENV=development prisma migrate deploy",
    "types": "tsc --noEmit",
  },
}

seed runs with --preload ./src/preload.ts — any direct bun src/<file> that imports app code needs the preload first, so the point0 compiler plugins are registered before that code loads (more on this below).

src/engine.ts — the engine config

Everything starts from one Engine.create(...) call. It declares SSR, where to find points, where to write generated code, and one config block per side (server, client):

// src/engine.ts (Bun-bundled form)
import { Engine } from '@point0/engine'
import { clientEnvKeys } from '@/lib/env/client-shape'

export const engine = Engine.create({
  file: import.meta.url, // engine anchors all relative paths to this file
  ssr: true,
  pointsGlob: '**/*.{ts,tsx,mdx}', // where points live
  generate: {
    meta: './generated/point0/meta.ts',
    assetsTypes: './generated/point0/assets.d.ts',
  },
  server: {
    scope: 'root',
    port: process.env.SERVER_PORT || process.env.PORT,
    entry: { main: './index.server.ts' },
    points: async () => await import('./generated/point0/points.server'),
    generate: { points: './generated/point0/points.server.ts' },
    outdir: '../dist/server',
  },
  client: {
    scope: 'root',
    port: process.env.CLIENT_PORT,
    indexHtml: './index.html',
    app: async () => await import('./app.client'),
    points: async () => await import('./generated/point0/points.client'),
    generate: {
      points: './generated/point0/points.client.ts',
      routes: {
        outfile: './generated/point0/routes.ts',
        origin: 'process.env.CLIENT_URL',
      },
    },
    bunPlugins: ['bun-plugin-tailwind'], // Vite mode replaces this with `viteConfig`
    env: { vars: clientEnvKeys }, // which env keys are bundled into the client
    publicdir: {
      source: '../public',
      outdir: '../dist/client',
    },
    outdir: '../dist/client',
  },
})

Every option here has a page: the full schema is engine-config, the codegen keys are generator, publicdir is publicdir, and env.vars is env. The examples/basic engine adds one extra block — client.compiler.babel: ['babel-plugin-react-compiler'] — which the template omits.

The four entry files

Around the engine sit four small files. Order is load-bearing in two of them.

src/preload.ts — registers the point0 compiler plugins and env constants. Anything that imports app code must run this first:

// src/preload.ts
import { engine } from '@/engine'

await engine.preload({ nodeEnvFallback: 'development' })

src/index.server.ts — the server entry (this is what start runs in production, as dist/server/index.server.js). Preload before app code, via dynamic imports so the order holds:

// src/index.server.ts
await import('./preload.js')
await import('./app.server.js') // imports @/engine and calls engine.serve()
export {}

app.server.ts validates the server env, then calls await engine.serve(). See engine-runtime for serve() and the rest of the engine instance.

src/app.client.tsx — the React app shell, default-exported. It nests the providers your points expect (react-query, unhead) and mounts the router:

// src/app.client.tsx
import { Router, RouterRoutes } from '@/lib/navigation'
import { UnheadProvider } from '@point0/core/unhead'
import { QueryClientProvider } from '@tanstack/react-query'
import { queryClient } from '@/lib/query-client'
import { Head } from '@unhead/react'

export default function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <UnheadProvider>
        <Head>
          {/* global head tags; per-page ones come from `.head(...)` on each point */}
          <link rel="shortcut icon" href="/favicon.ico" />
        </Head>
        <Router>
          <RouterRoutes />
        </Router>
      </UnheadProvider>
    </QueryClientProvider>
  )
}

src/index.client.tsx — the browser entry. It hands your App and the generated points to mount from @point0/react-dom/mount:

// src/index.client.tsx
import '@/lib/env/client' // validate client env before mounting
import App from '@/app.client'
import points from '@/generated/point0/points.client'
import '@/styles/index.css'
import { ErrorBoundary } from '@/ui/error-boundary'
import { mount } from '@point0/react-dom/mount'

mount(
  <ErrorBoundary>
    <App />
  </ErrorBoundary>,
  points,
)

if (import.meta.hot) {
  import.meta.hot.accept()
}

mount mounts into #root by default (it throws if #root is missing) and hydrates from the SSR-dehydrated store when one is present. index.html is the HTML template the client builds from — a #root div plus a <script type="module" src="./index.client.tsx">.

What else the scaffolder gives you

The four entry files above are the wiring; the rest of the template is the working example built on top of them:

  • src/lib/root.tsx — the root point (Point0.lets.root()...), where you set the transformer, schema helper, error class, prefetch policy, and global middleware like openapi. Every page and query grows from here.
  • src/lib/navigation.ts — the router wiring (createNavigation over wouter), exporting Link, navigate, Router, RouterRoutes, etc. See navigation.
  • src/lib/query-client.ts, src/lib/prisma.ts, src/lib/error.ts (a custom AppError class wired in via .errorClass(...) — the template builds it with Error0, but any compatible class works, and the default is ErrorPoint0), and the five-file src/lib/env/* system (shared / client / server env shapes and validators).
  • Example points: src/layouts/general.tsx (a layout), src/pages/home.tsx (a page), src/pages/about.mdx (an mdx page). The home page doubles as a playground: right in home.tsx it declares ideaListQuery (a query) over the Idea Prisma model and ideaCreateMutation (a mutation), plus a form that creates rows and invalidates the list. src/lib/seed.ts seeds three ideas (setup runs it).
  • src/generated/ — never hand-edited; produced by point0 generate and prisma generate, and gitignored. See generator.

Plus project-level files: package.json, tsconfig.json (with the @/* → ./src/* path alias), bunfig.toml, prisma.config.ts + prisma/schema.prisma, env.example, a Dockerfile, and .gitignore.

Gotcha — the template docker-compose.yml points at the monorepo. It references examples/basic (build context ../..), a stale artifact that does not work in a standalone generated app. Don't rely on docker compose from the scaffolded app until you rewrite it — see deploy for the real deploy path.

Reference

Scripts the CLI backs

ScriptCommandCLI page
devpoint0 dev --hotdev
buildpoint0 buildbuild
generatepoint0 generategenerator
startbun run ./dist/server/index.server.js (prod)deploy
setupprisma migrate + generate + point0 generate + seed—

Entry files

FileRole
src/engine.tsEngine.create(...) — the whole app config
src/preload.tsregisters compiler plugins + env consts (engine.preload)
src/index.server.tsserver entry; preload, then app.server (engine.serve)
src/app.client.tsxReact app shell (providers + router), default export
src/index.client.tsxbrowser entry; mount(<App/>, points)
НазадOverviewДалееFull Overview

Enjoying Point0?

Give it a star on GitHub, ask questions, and follow what's new

Star Point0

A star on GitHub helps more developers find Point0
Star on GitHub

Start0

Point0 integrated into the Start0 SaaS boilerplate — the best way to use it
Explore Start0

YouTube

Tutorials, walkthroughs, and updates
YouTube

Discord

Questions and chat in English
Join Discord

Telegram

News channel and chat in Russian
ChannelChat

Twitter

Posts and updates
Twitter