Development Guide
February 27, 2026 ยท View on GitHub
This guide helps you quickly master the projectโs development workflow and best practices.
๐๏ธ Project Architecture
Tech Stack
- Framework: Next.js 15.5.2 + App Router
- Language: TypeScript (strict mode)
- Styles: Tailwind CSS
- Runtime: Cloudflare Workers Edge Runtime
- Database: Cloudflare D1 (SQLite)
- Storage: Cloudflare R2
- Cache: Cloudflare KV
- Testing: Vitest
- Package Manager: pnpm
Directory Structure
cloudflare-worker-template/
โโโ app/ # Next.js app directory
โ โโโ api/ # API routes (Edge Runtime)
โ โโโ layout.tsx # Root layout
โ โโโ page.tsx # Home page
โโโ lib/ # Libraries
โ โโโ db/ # D1 DB wrapper
โ โโโ r2/ # R2 wrapper
โ โโโ cache/ # KV cache wrapper
โโโ components/ # React components
โโโ types/ # TypeScript types
โโโ migrations/ # DB migrations
โโโ scripts/ # Automation scripts
โโโ __tests__/ # Tests
๐ Development Workflow
1. Local Development
# Local development (runs in Workers runtime with Cloudflare bindings)
pnpm dev
2. Code Quality
The project enforces code quality:
# Format code
pnpm format
# Check formatting
pnpm run format:check
# ESLint
pnpm lint
# TypeScript typeโcheck
pnpm run type-check
3. TestโDriven Development
# Run all tests
pnpm test
# Watch mode (recommended during dev)
pnpm run test:watch
# Coverage
pnpm run test:coverage
๐ Writing Code
API Route Example
Create new API routes under app/api/:
// app/api/example/route.ts
import { NextRequest } from 'next/server';
import { withRepositories, successResponse } from '@/lib/api';
export const runtime = 'edge'; // Edge Runtime friendly
export async function GET(request: NextRequest) {
return withRepositories(request, async repos => {
// ไปๅจๅฑ่ด่ดฃๆฐๆฎๅบ่ฎฟ้ฎ๏ผAPI ๅชๅ
ณๆณจไธๅก้ป่พ
const users = await repos.users.findAll();
return successResponse(users, 'Users retrieved successfully');
});
}
Database Operations
import { NextRequest } from 'next/server';
import { withRepositories, successResponse } from '@/lib/api';
import { withCache } from '@/lib/cache/client';
export async function GET(request: NextRequest) {
return withRepositories(request, async repos => {
const users = await repos.users.findAll('asc');
const posts = await withCache(
'posts:latest',
() => repos.posts.findAll({ take: 5, published: true }),
300
);
return successResponse({ users, posts });
});
}
R2 Storage Operations
import { createR2Client } from '@/lib/r2/client';
const r2 = createR2Client();
// Upload file
await r2.put('uploads/file.jpg', fileData, {
httpMetadata: { contentType: 'image/jpeg' },
});
// Download file
const object = await r2.get('uploads/file.jpg');
const blob = await object.blob();
// Delete file
await r2.delete('uploads/file.jpg');
// List files
const list = await r2.list({ prefix: 'uploads/' });
KV Cache Operations
import { withCache } from '@/lib/cache/client';
// Use cache wrapper
const data = await withCache(
'cache-key',
async () => {
// Expensive operation
return await fetchExpensiveData();
},
3600 // TTL (seconds)
);
๐๏ธ Database Management
The project uses Wrangler D1 migrations to manage schema, and Prisma for typeโsafe queries. In daily dev:
- Use
pnpm run db:migrations:createto generate a migration - Run
pnpm run db:migrate:local/pnpm run db:migrate:test/pnpm run db:migrate:prod - After schema changes, update
prisma/schema.prismaand runpnpm prisma:generate
Naming conventions, rollback strategy, and data migration scripting are detailed in Migrations Guide.
๐งช Writing Tests
Unit Test Example
// __tests__/lib/my-feature.test.ts
import { describe, it, expect, vi } from 'vitest';
import { myFunction } from '@/lib/my-feature';
describe('My Feature', () => {
it('should work correctly', () => {
const result = myFunction('input');
expect(result).toBe('expected output');
});
it('should handle errors', () => {
expect(() => myFunction(null)).toThrow();
});
});
Mock Cloudflare Bindings
const mockDB = {
prepare: vi.fn().mockReturnThis(),
bind: vi.fn().mockReturnThis(),
all: vi.fn().mockResolvedValue({ results: [] }),
} as any;
๐ Git Workflow
Branching Strategy
mainโ production (auto deploy)developโ test (auto deploy)feature/*โ feature developmentfix/*โ bug fixes
Commit Conventions
Use Conventional Commits:
feat: add user authentication
fix: fix file upload issue
docs: update API docs
test: add user tests
refactor: refactor DB queries
style: format code
chore: update dependencies
Release Management
The project uses automated CHANGELOG generation via release-please. To trigger a release:
Include [release] in your commit message:
# Regular commits (not included in immediate CHANGELOG)
git commit -m "feat: add new feature"
git commit -m "fix: resolve bug"
# Release commit (triggers CHANGELOG PR creation)
git commit -m "chore: prepare v1.2.0 release [release]"
What happens when you use [release]:
- โ
GitHub Actions detects the
[release]tag - โ
release-pleasescans all commits since the last release - โ
Automatically creates a PR with:
- Updated
CHANGELOG.md(all feat/fix/docs commits) - Version bump in
package.json(following semver)
- Updated
- โ Merge the PR to publish the release
Best practices:
- Use
[release]only when you're ready to cut a new version - All feature/fix commits between releases will be included automatically
- No need to manually update CHANGELOG or version numbers
Development Flow
# 1. Create a feature branch
git checkout -b feature/awesome-feature
# 2. Develop and test
pnpm dev
pnpm test
# 3. Commit code
git add .
git commit -m "feat: add awesome feature"
# 4. Push to remote
git push origin feature/awesome-feature
# 5. Open a Pull Request
# CI runs tests automatically
โ๏ธ GitHub Actions Setup
Enable Workflow Permissions
To allow GitHub Actions to automatically create pull requests (e.g., for CHANGELOG updates via release-please), configure repository settings:
-
Navigate to repository settings:
- Go to your repository:
https://github.com/YOUR_USERNAME/YOUR_REPO - Click Settings in the top menu
- Go to your repository:
-
Configure Actions permissions:
- In the left sidebar, click Actions โ General
- Or directly visit:
https://github.com/YOUR_USERNAME/YOUR_REPO/settings/actions
-
Update Workflow permissions:
Scroll to the "Workflow permissions" section at the bottom:
โ Read repository contents and packages permissions โ Read and write permissions โ Select this โ Allow GitHub Actions to create and approve pull requests โ Check this -
Save settings:
- Click Save to apply changes
Why This Is Required
By default, GitHub restricts Actions from creating pull requests for security. Our automated workflows need these permissions to:
- Auto-update CHANGELOG: The
release-pleaseworkflow creates PRs with version updates - Dependency updates: Automated dependency update bots (e.g., Dependabot, Renovate)
- Code generation: Workflows that auto-generate code and create PRs
๐ง Troubleshooting
View logs
# View Cloudflare Workers logs in real-time
wrangler tail
Local DB queries
wrangler d1 execute cloudflare-worker-template-local --local \
--command="SELECT * FROM users"
Common issues
pnpm install failed?
pnpm store prune && pnpm install
Type errors?
pnpm run type-check
Tests failing? Check Cloudflare bindings are configured correctly.
Local DB is empty?
pnpm run db:migrate:local
pnpm run db:seed -- --env=local