Quick start
Mount the docs UI on your existing app in under five minutes.
Pick your framework. Each example mounts the docs UI at /docs next to your
existing router — no rewrite required.
const express = require('express');
const { expressAdapter } = require('doctreen/express');
const app = express();
app.use(express.json());
app.get('/users', (req, res) => res.json([]));
app.post('/users', (req, res) => res.status(201).json({ id: 1 }));
// Mount after your routes
app.use(expressAdapter(app, {
meta: { title: 'My API', version: '1.0.0' },
}));
app.listen(3000, () => console.log('Docs at http://localhost:3000/docs'));const fastify = require('fastify')();
const { fastifyAdapter } = require('doctreen/fastify');
// Call BEFORE registering routes — uses the onRoute hook
fastifyAdapter(fastify, {
meta: { title: 'My API', version: '1.0.0' },
});
fastify.get('/users', async (req, reply) => reply.send([]));
fastify.listen({ port: 3000 });// Hono v4 is ESM-only — run with: npx tsx hono-app.js
import { Hono } from 'hono';
import { serve } from '@hono/node-server';
import { honoAdapter } from 'doctreen/hono';
const app = new Hono();
app.get('/users', (c) => c.json([]));
// Can be called before or after routes
honoAdapter(app, { meta: { title: 'My API', version: '1.0.0' } });
serve({ fetch: app.fetch, port: 3000 });const Koa = require('koa');
const Router = require('@koa/router');
const { koaAdapter } = require('doctreen/koa');
const app = new Koa();
const router = new Router();
router.get('/users', (ctx) => { ctx.body = []; });
// Can be called before or after routes
koaAdapter(router, { meta: { title: 'My API', version: '1.0.0' } });
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { nestAdapter } from 'doctreen/nest';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Call after NestFactory.create(), before app.listen()
nestAdapter(app, {
meta: { title: 'My API', version: '1.0.0' },
});
await app.listen(3000);
console.log('Docs at http://localhost:3000/docs');
}
bootstrap();Then annotate your controller methods with @DocRoute — see
NestJS adapter.
from flask import Flask
from doctreen.adapters.flask import flask_adapter
app = Flask(__name__)
@app.get("/users")
def list_users():
return []
# Mount anywhere — routes registered later are still picked up.
app.register_blueprint(flask_adapter(app, {
"meta": {"title": "My API", "version": "1.0.0"},
}))
# flask run → docs at http://localhost:5000/docsThen annotate your views with @define_route — see
Flask adapter.
from fastapi import FastAPI
from doctreen.adapters.fastapi import mount_doctreen
app = FastAPI(title="My API", version="1.0.0")
@app.get("/users")
def list_users():
return []
# Reads app.openapi() — FastAPI's own /docs stays untouched.
mount_doctreen(app, {"drift": {"enabled": True}})
# uvicorn main:app → DocTreen UI at http://localhost:8000/doctreenFastAPI keeps its own docs and validation; DocTreen adds drift detection and the shared UI — see FastAPI adapter.
# urls.py
from django.urls import include, path
from doctreen.adapters.django import doctreen_urls
urlpatterns = [
path("api/", include(router.urls)),
*doctreen_urls({"meta": {"title": "My API", "version": "1.0.0"}}),
]
# settings.py — only needed for drift sampling
MIDDLEWARE = [..., "doctreen.adapters.django.DocTreenMiddleware"]
# python manage.py runserver → docs at http://localhost:8000/docsSchemas come from your DRF serializers — see Django / DRF adapter.
// Nothing to mount: the service provider is auto-discovered by Composer,
// and GET /docs + GET /docs/openapi.json are registered automatically.
// Optionally publish the config to customise title, path, validation, drift:
// php artisan vendor:publish --tag=doctreen-config
// routes/api.php — document a route with the ->doc() macro:
use Doctreen\Schema\S;
Route::get('/users', [UserController::class, 'index'])->doc([
'description' => 'List users',
'response' => S::array(S::object(['id' => S::number(), 'name' => S::string()])),
]);
// php artisan serve → docs at http://localhost:8000/docsSee the Laravel adapter for validation, drift, and the CLI.
Visit the configured docsPath (default: /docs) to see your documentation.
Next steps
- Configure the docs path, groups, and metadata
- Turn on Runtime validation
- Export to OpenAPI 3.1