# Crowi v2 rebuilds the Markdown wiki on Hono and Next.js while keeping the v1 MongoDB shape

> Crowi is a team wiki where the URL path is the page hierarchy, and the v2 Reignite rewrite swaps Express, Swig and jQuery for a Hono API, Next.js 16 and React 19 while leaving the MongoDB data shape intact. It fits a team migrating an existing wiki, and it does not fit anyone who needs a stable release, since v2 is still in alpha and v1 is deprecated.

**crowi/crowi** — Crowi - The Markdown Wiki - Empower the team with sharing your knowledge

- Repository: https://github.com/crowi/crowi
- Website: https://crowi.wiki
- Stars: 1,098 · Forks: 165
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/crowi-crowi

## The URL is the page, so a wiki reads like a path

Crowi is a Markdown wiki for team knowledge sharing, and the design decision that defines it is that URL paths are the page hierarchy. A page at /team/handbook/onboarding reads exactly the way it is written, with no separate tree widget to maintain and no index page to keep in sync. The Markdown is the storage format, so pages are diffable, greppable and portable, which is what a team wiki is actually for.

The v2 rewrite keeps that idea and changes almost everything underneath. The README describes the stack as moving from Express plus Swig plus jQuery to a Hono API plus Next.js 16 with the App Router plus React 19. The data shape is deliberately left alone: the README states that v1's MongoDB data shape stays intact so an existing wiki migrates over.

That constraint is the whole point of the v2 work. A rewrite that required a data migration would be a different product with a different risk profile. Keeping the shape means the migration is a code change, not a content change, which is a much smaller thing to test and to roll back.

The 2.0 codename is Reignite, and the README states the project is in active prerelease. v1.x is deprecated and unmaintained.

## Plugins are resolved at runtime, so the API is never rebuilt

The architecture that makes v2 operationally interesting is the pluggable driver set: storage, search, renderer and mail are all plugins, and the API package is plugin-agnostic at runtime. The resolution mechanism is specific. @crowi/runner resolves plugin npm names against the runner project's node_modules using createRequire(<projectDir>/package.json).

The operator workflow follows from that. You add a plugin by declaring it in your runner's package.json dependencies and listing it in crowi.config.json:plugins, and the api never needs to be rebuilt. The repository ships the full set of default and alternative drivers: plugin-storage-local as the default-on local filesystem driver, plugin-storage-aws-s3, plugin-search-elasticsearch, plugin-search-opensearch, plugin-search-mongo for MongoDB-native search with no external service, plugin-mail-smtp, plugin-mail-resend, plugin-mail-aws-ses, and renderers for KaTeX math, PlantUML diagrams, and a crowi-legacy renderer for v1-era wikilinks and strikethrough.

Two runners exist in the apps directory. crowi-runner is the reference runner project that owns @crowi/api plus the full plugin set and crowi.config.json, and it is the build source for the full Docker image. crowi-runner-slim is the minimal runner used as the build source for the slim Docker image, with the core and a minimal plugin set. The operator picks a runner, and the runner picks the drivers.

## Local development needs a signing secret the API refuses to boot without

The README documents a five step local setup, and the fourth step is the one that catches people. The API refuses to boot without a generated signing secret, and the documented way to produce it is:

```bash
# 4. Generate the required signing secret — the api refuses to boot without it
openssl rand -base64 32   # paste the output into .env as SECRET_TOKEN=...
```

The rest of the sequence is dependencies, infrastructure, an env file and the dev command. pnpm install fetches the workspace, docker compose up -d starts MongoDB, Redis, Elasticsearch and PlantUML, and cp .env.example .env creates the env file at the repo root. The .env.example lists the values to edit, including MONGO_URI, REDIS_URL, PASSWORD_SEED and CROWI_ENCRYPTION_KEY.

There is a subtlety in the env loading worth knowing before you debug it. pnpm dev boots the API with cwd set to apps/crowi-runner, the runner projectDir, so its dev script loads the repo-root .env via --env-file-if-exists=../../.env. In production or in an external runner project, the API reads the .env in its own cwd through dotenv instead. A .env in the wrong place is therefore not obviously wrong.

The stack requirements are Node.js 24.x, pnpm 10.x pinned via packageManager, MongoDB, Redis, an optional plugin-driven search backend, and Docker with Docker Compose for local infrastructure. The dev command starts the API on port 4301 and the web frontend on port 4302, with the crowi.wiki site on port 4303.

## Redis is optional for one instance and required for several

The .env.example is unusually detailed about REDIS_URL, and the detail is the specification. REDIS_URL is optional for single-instance deployments and required for multi-instance ones, with every instance pointing at the same Redis, since page content always lives in MongoDB and never in Redis.

What Redis backs is eight consumers: collab pub/sub, an editor-cap counter, presence, notification invalidation, Config sync, rate limiting, an LRU, and account linking. Each has its own degrade behaviour when the variable is unset, and the docs point to the operations/realtime-collab section for the per-consumer table.

One consumer behaves differently from the rest, and it is worth knowing which. Account linking fails closed rather than degrading. With CROWI_MULTI_INSTANCE declared and no Redis client, the very first link request returns a 500 before issuing any cookie, authorization URL or confirmation code, because the flow never started and there is nothing to lose visibility on another replica. Set REDIS_URL to enable account linking under multi-instance.

The key namespacing matters for operators sharing infrastructure. Every Redis key and channel is built through an instance-scoped namespace of crowi:<slug>:<suffix>, so multiple Crowi instances can share one Redis without cross-talk. The slug defaults to the hostname of CLIENT_URL, and REDIS_KEY_PREFIX overrides it explicitly. The rule that follows is asymmetric: every replica of the same instance must resolve to the same effective prefix, while different instances sharing a Redis must use different prefixes.

## Yjs, an MCP server and PATs are what v2 adds for agents

The v2 highlights list names the pieces that are new rather than rewritten. Real-time collaborative editing runs on Yjs and Hocuspocus in the @crowi/collab package, which is attached to the API process rather than run as a separate service. An embedded Model Context Protocol server is included for AI agents, which is a notable thing to find built into a wiki. Authentication is OAuth 2.0 plus personal access tokens, with JWT auth through the jwtAuth middleware on the API side.

The CLI is split in two and the split is meaningful. @crowi/cli is the end-user CLI that reads, writes and searches over the HTTP API, published as @crowi/cli@1.0.0-alpha.8. crowi-admin is a separate DB-direct CLI for init, migrate and re-encrypt. The distinction is between going through the API and going around it, and the admin tool is the one you reach for when the API cannot start because the data needs migrating or a secret needs re-encrypting.

Sensitive configuration is encrypted with AES-256-GCM, and there is a CONFIG sync consumer on Redis to keep configuration consistent between instances. The v1-era renderer plugin exists to keep v1 wikilinks and strikethrough rendering correctly after the migration, which tells you the migration is expected to preserve rendering behaviour rather than only data.

## Deployment runs through two runner images and a compose profile

The docker-compose.yml separates infrastructure from application services. The default docker compose up -d starts only the dev infrastructure dependencies, MongoDB, Redis, Elasticsearch and Mailpit, and you then run pnpm dev on the host against that infrastructure. To run the whole stack inside Docker, api plus web plus infra, the compose file provides an app profile, started with docker compose --profile app up -d --build.

The build sources are the two runner projects. The API image is built from the @crowi/runner-app reference runner project at apps/crowi-runner and bakes that project's crowi.config.json into the image. Driver selection can be overridden without a rebuild, because the api service re-mounts apps/crowi-runner/crowi.config.json at /app/crowi.config.json, which the compose file describes as operator-controlled. That is a small but important property: changing drivers does not mean rebuilding an image.

The compose file also pins the Redis image by digest, redis:8.8.0 with a sha256, and the comment marks it as the single source for the pinned engine that ci.yml's REDIS_IMAGE must match. The MongoDB service uses mongo:8, and a separate test-only MongoDB service exists because a full API test run opens a large number of connections against one shared mongod, with a comment that puts that on the same server and disk path as the dev service is a contributor to stall windows.

Other infrastructure files at the root include a Caddyfile, an elasticsearch.Dockerfile, an elasticsearch directory, turbo.json for the Turborepo pipeline, and lefthook.yml for the git hooks.

## The v1 to v2 boundary is the decision to make

The README is unusually direct about the state of the project, and the caution block should be read as the adoption contract. Alpha prereleases are published and support an in-place upgrade from a v1 MongoDB, but there is no stable v2 yet, so the API and config surface can still change between alphas. The instruction is to pin a specific version from the releases and read the notes, and for a real deployment to use a published release rather than the branch's HEAD.

That is the whole risk profile in three sentences. An in-place upgrade path means a v1 installation can move to v2 without a data migration, which is a genuine benefit and the reason to consider it now. The prerelease status means the surface you adopt is not frozen, which is the reason to wait if you cannot absorb a breaking change.

There is also no third option, because Crowi v1.x is deprecated and unmaintained. A team that stays on v1 is choosing a codebase that will not receive fixes. The releases show the pace of the rewrite: v2.0.0-alpha.23, @crowi/api@2.0.0-alpha.24 and @crowi/cli@1.0.0-alpha.8 all published on 2026-10-12, with the last push on the same day. Progress is tracked in the releases, the docs at crowi.wiki, and a v2 announcement on Zenn.

The licence is MIT, and the project is authored by Sotaro Karasawa with contributors including lightnet328, otofune and Norio Suzuki. The tests are Jest with supertest and mongodb-memory-server for the API and collab packages, linting is Biome for format and ESLint for lint, and the shared code is TypeScript 5.x in strict mode.

## Conclusion

Crowi v2 fits a team that already runs a Crowi v1 wiki on MongoDB and wants collaborative editing, token-based access for agents and pluggable storage without migrating its data, and it does not fit a team that needs a stable, supported release today. Before adopting it, pin a specific alpha version from the releases page and read its notes, because the README warns the API and config surface can still change between alphas, and note that v1.x is deprecated and unmaintained, so the v2 path is the only forward path even though it is prerelease.

## FAQ

### What is Crowi v2 Reignite?

Crowi v2, codenamed Reignite, is a rewrite of the Markdown wiki from Express, Swig and jQuery to a Hono API, Next.js 16 with the App Router, and React 19. It keeps v1's MongoDB data shape intact, so an existing wiki migrates over without a data migration.

### Is Crowi v2 stable yet?

No. The README states that Crowi v2 is in active prerelease, that alpha prereleases are published and support an in-place upgrade from a v1 MongoDB, and that there is no stable v2 yet, so the API and config surface can still change between alphas. Crowi v1.x is deprecated and unmaintained.

### How do I add a storage or search plugin to Crowi v2?

You declare the plugin in your runner project's package.json dependencies and list it in crowi.config.json:plugins. The runner resolves plugin npm names against the runner project's node_modules, and the api never needs to be rebuilt.

### Is Redis required for a Crowi v2 deployment?

REDIS_URL is optional for single-instance deployments and required for multi-instance ones, where every instance must point at the same Redis. Page content always lives in MongoDB. Account linking fails closed under multi-instance without a Redis client, so the first link request returns a 500 before any cookie is issued.

### What does Crowi v2 require to run locally?

Node.js 24.x, pnpm 10.x, MongoDB, Redis, an optional search backend, and Docker with Docker Compose for the local infrastructure. The API also refuses to boot without a signing secret, generated with openssl rand -base64 32 and pasted into .env as SECRET_TOKEN.

## Sources

- [crowi/crowi on GitHub](https://github.com/crowi/crowi)
- [License: MIT](https://github.com/crowi/crowi/blob/main/LICENSE)
- [Project website](https://crowi.wiki)
- [README](https://github.com/crowi/crowi/blob/main/README.md)
- [Releases](https://github.com/crowi/crowi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/crowi-crowi
