How to Create a New Kaneo Project: Complete API and Web Client Guide
You create a new Kaneo project by sending a POST request to /api/project with a name and workspaceId, authenticated via Bearer token.
In Kaneo, a project serves as the top-level container for tasks, columns, and labels. Whether you're building a custom integration or extending the web interface, understanding the project creation flow is essential. This guide walks through the API endpoint, database schema, and React hooks that power this feature in the usekaneo/kaneo open-source project management platform.
API Endpoint: Creating Projects via HTTP
The canonical way to create a new Kaneo project is through the REST API endpoint defined in apps/api/src/project/index.ts.
Request Requirements
| Requirement | Details |
|---|---|
| Method | POST |
| URL | /api/project |
| Authentication | Bearer token (device flow or API key) |
| Content-Type | application/json |
Request Payload
The payload is validated using Valibot and requires two fields:
name(string): Display name for the projectworkspaceId(string): CUID2 identifier of the parent workspace
cURL Example
curl -X POST "$KANEO_API_URL/api/project" \
-H "Authorization: Bearer $YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Q4 Marketing Campaign","workspaceId":"cuid-workspace-123"}'
Expected Response
{
"id": "cuid-project-xyz",
"name": "Q4 Marketing Campaign",
"workspaceId": "cuid-workspace-123",
"createdAt": "2026-08-05T12:34:56.789Z",
"updatedAt": "2026-08-05T12:34:56.789Z"
}
The endpoint is registered with Hono and protected by Better Auth middleware as defined in apps/api/src/auth/middleware.ts. No request reaches the project creation logic without passing authentication.
Database Schema: How Projects Are Stored
Projects persist in PostgreSQL through the Drizzle ORM schema defined in apps/api/src/database/schema.ts. The projectTable structure includes:
- Primary key: CUID2 auto-generated identifier
- Timestamps:
createdAtandupdatedAtwith automatic updates - Foreign key:
workspaceIdreferencingworkspaceTablewithonDelete: cascadeandonUpdate: cascade
This cascade behavior ensures that deleting a workspace automatically removes all associated projects, maintaining referential integrity without manual cleanup.
Web Client Integration: React Hooks and Fetchers
The Kaneo web application abstracts API calls into typed fetchers and TanStack Query mutations.
Fetcher Layer
The createProject function in apps/web/src/fetchers/project/create-project.ts wraps the API client:
import { apiClient } from "@/lib/api-client";
export async function createProject(data: {
name: string;
workspaceId: string;
}) {
const response = await apiClient.post("/project", data);
return response.json();
}
React Mutation Hook
The useCreateProject hook in apps/web/src/hooks/mutations/project/use-create-project.ts exposes this as a full-featured mutation with loading states, error handling, and automatic cache invalidation:
import { useCreateProject } from "@/hooks/mutations/project/use-create-project";
function NewProjectButton({ workspaceId }: { workspaceId: string }) {
const createProject = useCreateProject();
const handleClick = async () => {
await createProject.mutateAsync({
name: "Website Redesign",
workspaceId
});
};
return (
<button
onClick={handleClick}
disabled={createProject.isLoading}
>
{createProject.isLoading ? "Creating…" : "Create Project"}
</button>
);
}
Key behaviors:
isLoadingprovides immediate UI feedbackmutateAsyncreturns a Promise for sequential operations- On success, the project list query invalidates automatically
Running the Complete Stack Locally
Kaneo uses Turborepo to orchestrate the monorepo. Start both API and web servers:
pnpm install
pnpm dev
This concurrently launches:
- API server at
http://localhost:1337(configurable viaKANEO_API_URL) - Vite dev server for the web interface
For production deployment, reference the compose.yml at the repository root for Docker Compose configuration.
Key Implementation Files
| Component | Path |
|---|---|
| API route handler | apps/api/src/project/index.ts |
| Database schema | apps/api/src/database/schema.ts |
| Web API fetcher | apps/web/src/fetchers/project/create-project.ts |
| React mutation hook | apps/web/src/hooks/mutations/project/use-create-project.ts |
| Authentication middleware | apps/api/src/auth/middleware.ts |
Summary
- Create a new Kaneo project via
POST /api/projectwithnameandworkspaceId - Authentication is mandatory — include a valid Bearer token from Better Auth
- API is fully typed through Valibot validation and Drizzle schema
- Web client abstracts complexity through
createProjectfetcher anduseCreateProjecthook - Local development runs both services via
pnpm devin Turborepo
Frequently Asked Questions
What authentication methods does Kaneo accept for project creation?
Kaneo accepts Bearer tokens from two sources: device flow authentication for interactive users and API keys for service accounts. The Better Auth middleware in apps/api/src/auth/middleware.ts validates tokens on every request to /api/project. No anonymous project creation is permitted.
Can I create a project without using the React web interface?
Yes. The API endpoint is client-agnostic. Any HTTP client — curl, Python requests, Node.js fetch, or an MCP server — can POST to /api/project with proper authentication. The web interface is one consumer of many possible clients.
What happens to projects when I delete a workspace?
Projects cascade automatically. The projectTable schema defines onDelete: cascade on the workspaceId foreign key, so deleting a workspace removes all child projects, tasks, and related data in a single database transaction.
Does Kaneo support bulk project creation?
The core API handles single project creation. For bulk operations, implement client-side batching by calling POST /api/project multiple times, or extend the API route in apps/api/src/project/index.ts to accept an array payload with a custom validation schema.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →