Getting Started

Get up and running with Nanoka in minutes.

1. Prerequisites

Start from a Hono project targeting Cloudflare Workers:

npm create hono@latest my-api
# Select: cloudflare-workers template
cd my-api

2. Install dependencies

pnpm add @nanokajs/core drizzle-orm zod
pnpm add -D drizzle-kit @cloudflare/workers-types

3. Configure TypeScript

Add the Cloudflare Workers types to tsconfig.json:

{
  "compilerOptions": {
    "types": ["@cloudflare/workers-types"]
  }
}

4. Define a model

Create src/models/user.ts:

import { t } from '@nanokajs/core'

export const userTableName = 'users'

export const userFields = {
  id:           t.uuid().primary().readOnly(),
  email:        t.string().email().unique(),
  name:         t.string(),
  passwordHash: t.string().serverOnly(),
  createdAt:    t.timestamp().readOnly(),
}
  • readOnly() — excluded from create/update inputs; UUID is auto-generated on create().
  • serverOnly() — stored in the DB but never included in API responses.

5. Create nanoka.config.ts

import { defineConfig } from '@nanokajs/core/config'
import { userFields, userTableName } from './src/models/user'

export default defineConfig({
  models: [{ name: userTableName, fields: userFields }],
  output: './drizzle/schema.ts',
})

6. Generate the Drizzle schema

npx nanoka generate

This writes src/db/schema.ts — a standard Drizzle schema file you can inspect and commit.

7. Create drizzle.config.ts

import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './migrations',
  dialect: 'sqlite',
  driver: 'd1-http',
})

8. Apply migrations

Option A — unified pipeline (recommended):

# Generate schema, run drizzle-kit, and apply to local D1 in one command
npx nanoka generate --apply --db <DATABASE_NAME>

# Apply to remote D1
npx nanoka generate --apply --db <DATABASE_NAME> --remote

Option B — step by step:

# 1. Generate Drizzle schema
npx nanoka generate

# 2. Generate SQL migration files
npx drizzle-kit generate

# 3a. Apply locally
npx wrangler d1 migrations apply <DATABASE_NAME> --local

# 3b. Apply to remote
npx wrangler d1 migrations apply <DATABASE_NAME> --remote

9. Minimal src/index.ts

import { nanoka, d1Adapter } from '@nanokajs/core'
import { userFields, userTableName } from './models/user'

export interface Env {
  DB: D1Database
}

export default {
  async fetch(req: Request, env: Env, ctx: ExecutionContext) {
    const app = nanoka<{ Bindings: Env }>(d1Adapter(env.DB))
    const User = app.model(userTableName, userFields)

    app.get('/users', async (c) => {
      const users = await User.findMany({ limit: 20, offset: 0, orderBy: 'createdAt' })
      return c.json(User.toResponseMany(users))
    })

    app.post('/users', User.validator('json', 'create'), async (c) => {
      const body = c.req.valid('json')
      const user = await User.create(body)
      return c.json(User.toResponse(user), 201)
    })

    return app.fetch(req, env, ctx)
  },
}

10. Add D1 binding to wrangler.jsonc

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "<DATABASE_NAME>",
      "database_id": "<DATABASE_ID>"
    }
  ]
}

Create the database if you haven't already:

npx wrangler d1 create <DATABASE_NAME>

11. Start the local dev server

pnpm dev

Wrangler starts a local D1 instance automatically. Hit http://localhost:8787/users to verify.

12. Scaffold a full project instantly

To skip all the manual setup above, use the interactive scaffolder:

pnpm create nanoka-app my-app

This generates a ready-to-run project with a User model, migrations config, Wrangler config, and all dependencies pre-configured.