Build an internal knowledge base without Confluence
· Avery NXR
Confluence is bloated. Notion is great for ideas but bad for runbooks. Most teams have both. Neither works well for what they're actually trying to do.
The mistake is forcing one tool to do everything. Creative writing and structured operational documentation are different problems. Confluence solves neither well anymore. Notion solves creative work well but treats every page as freeform, which is wrong for runbooks, ADRs, postmortems, and on-call procedures.
A custom internal knowledge base, built in a week with Avery, solves the structured documentation problem. Keep Notion for everything else.
This isn't a "let's replace all our wikis" post. This is a "let's build the structured-documentation tool that Confluence and Notion both fail at" post.
What internal documentation actually needs
The functional requirements for the operational documentation use case:
Markdown editing. With code block syntax highlighting and tables. That's it. No collaborative cursors needed for operational docs.
Full-text search. Across page bodies, titles, and tags. Fast enough that searching is the default discovery method, not browsing.
Role-based access. Engineering sees engineering docs. Operations sees operations docs. Everyone sees company-wide.
Version history. Who changed what, when. Crucial for runbooks where the wrong version can break production.
Structured templates. A runbook has specific sections (trigger, diagnosis, recovery, escalation). An ADR has specific sections (context, decision, consequences). A postmortem has specific sections (timeline, root cause, action items). The system enforces structure.
Slack integration. Share links to pages cleanly. Optional: auto-post to a Slack channel when a page in a watched category changes.
That's the system. Eight to ten CRs.
Why Confluence and Notion both fail
Confluence's failure mode: feature bloat. The original use case (team wiki) is buried under a thousand integrations, dashboards, and Atlassian Marketplace plugins. Search is slow. The editor is heavy. Permissions are powerful and incomprehensible. The cost per user grows linearly with the team.
Notion's failure mode: structural ambiguity. Every page is a blank canvas. This is fine for project planning and creative writing. It is bad for operational documentation where structure is the point. A runbook without sections isn't a runbook, it's a journal entry. Notion treats databases as the structure mechanism, but databases are a clumsy fit for documentation. They constrain when they should guide.
The custom build splits the difference. Specific page types with enforced structure. Lightweight markdown editing. Fast search. Cheap to run. Owned end to end.
The Avery build
CR 1: Page data model.
"Build a Page model with id, title, slug (unique), content_markdown, page_type (enum: doc, runbook, adr, postmortem, faq), category (FK), author_id, status (enum: draft, published, archived), created_at, updated_at. Add migrations and types."
CR 2: Categories and hierarchical organization.
"Build a Category model with id, name, slug, parent_id (self-FK for nesting), description, default_page_type. Pages belong to one category. Categories can nest two levels deep (e.g., Engineering > On-call > Database)."
CR 3: Structured templates.
"When creating a new page, prompt for page_type. For each type, pre-fill the content_markdown with structured sections: 'doc' uses no template. 'runbook' uses [When this fires, How to diagnose, Recovery steps, Escalation, Related docs]. 'adr' uses [Context, Decision, Consequences, Alternatives considered]. 'postmortem' uses [Summary, Timeline, Root cause, What went well, What didn't, Action items]. Templates are markdown headers."
CR 4: Full-text search.
"Add a tsvector column to Page indexing title, content_markdown, category name. Use Postgres full-text search via to_tsquery. Build /search route accepting a query string, returning ranked results with title, category, snippet of matching content, last updated date. Search must complete in under 200ms for the typical corpus."
CR 5: Page edit and preview.
"Build /pages/[slug]/edit with a markdown editor (textarea-based, no fancy WYSIWYG needed) and a live preview pane. On save, increment version number and store the previous content in a PageVersion table."
CR 6: Version history.
"Build /pages/[slug]/history showing all PageVersions with author, timestamp, and a 'view' link that renders that version. Diff view between any two versions. Allow rollback to any previous version (creates a new version)."
CR 7: Role-based access.
"Add RolePermission per Category: role (admin, engineering, operations, all), permission (read, write, admin). Pages inherit permissions from their category. Enforce at API: returning 403 if user lacks read; UI: hiding edit buttons if user lacks write. Admin can override all."
CR 8: Slack integration.
"Build /api/slack/share-page endpoint that takes a page slug, generates a nicely formatted Slack message with title, category, summary, and link, and posts to a configured channel. Build a watched-categories system: when a page in a watched category is updated, auto-post a digest to a specified Slack channel."
CR 9: Page browsing and homepage.
"Build / showing recently updated pages, pages owned by current user, watched categories, search bar. Build /categories/[slug] showing all pages in that category sorted by last updated, with filter by page_type."
CR 10: Migration tooling.
"Build /admin/import accepting markdown files (or a folder of markdown files) and inserting them as Pages with frontmatter-based metadata. Frontmatter fields: title, page_type, category. This lets you migrate from existing wikis or git-based docs."
Ten CRs. Five focused days.
What this is for, and what it isn't
This tool is for: runbooks, ADRs, postmortems, on-call procedures, deployment guides, troubleshooting docs, architecture overviews, service catalogs, internal FAQs.
This tool is not for: project planning (use Notion or Linear), meeting notes (use Notion or Google Docs), creative writing or brainstorming (use Notion), customer-facing documentation (use a docs site generator like Docusaurus or Mintlify).
Trying to make it serve all use cases is how you end up with Confluence again.
Why the structure enforcement matters
A runbook that's missing the escalation section will get you paged at 2 AM and you'll have no idea who to call. A runbook that's missing the diagnosis section will have you guessing.
Confluence and Notion let you write a "runbook" that's just paragraphs of unstructured text. The author thought it was complete. The on-call engineer disagrees at 2 AM.
The custom build enforces sections. You cannot publish a runbook without filling in the required sections. The friction is the point. Structured docs catch the missing pieces before they bite you.
The search problem
Internal documentation is only as good as your ability to find what you need quickly. Confluence's search is famously slow. Notion's search is usable but ranks oddly.
Postgres full-text search, used directly, handles up to about 10,000 pages with sub-200ms latency on a modest server. That's enough for most company knowledge bases.
Beyond 10,000 pages, you'll want Elasticsearch or Meilisearch. That's a v2 problem.
The unlock is making search the default. If your knowledge base has a 200ms search bar at the top of every page, people will search instead of browse. Browsing fails as the corpus grows; search scales.
Things that surprise people
Migration from existing tools is the slow part. Confluence to markdown is doable with tools like confluence-markdown-exporter, but the result needs cleanup. Budget two or three days for migration if you're moving from Confluence with significant content.
The Slack integration is more important than it looks. The way most teams discover documentation is through Slack: someone posts a link. Making that flow clean (nice previews, watched-categories digests) drives adoption.
Version history sounds boring but is critical for runbooks. If a runbook was edited yesterday and now production is broken, you need to see what changed. Roll back capability is the trust mechanism.
The page-type templates are the design unlock. People resist structure until they see what it produces. A team that's been writing freeform "runbooks" for a year and starts using a structured template will produce better runbooks within a week.
What this costs to run
Vercel or Railway: $20 to $40 per month.
Postgres: $25 to $50 per month with full-text search included.
Slack webhook integration: free.
No third-party document storage costs (markdown lives in Postgres).
Total: $45 to $90 per month.
Versus Confluence at per-user pricing that scales to hundreds or thousands per month for medium teams.
The savings compound quickly. A team of 50 paying Confluence Standard is paying ~$300 per month. The custom build's first year of operation is less than two months of Confluence.
When to keep using Notion
Project planning. Meeting notes. Roadmaps. Anything that benefits from flexibility over structure.
Notion's strength is the blank canvas. Don't try to replace that. Use it for what it's good at.
The split: structured operational docs in the custom build. Everything else in Notion. Both linked from a central index in whichever tool serves as your team's homepage.
When the custom build isn't worth it
Team under 10 people. Notion alone is fine at small scale.
You have no consistent on-call rotation, no recurring postmortems, no architectural decisions to track. The structured-docs problem doesn't exist for you yet.
You don't have technical capacity to maintain a custom tool. Even with Avery handling future CRs, you need someone to be the owner.
For most companies of 25 to 500 employees with operational complexity, the custom build pays off quickly.
The v1.1 additions
Comments on pages. Inline review and discussion. Two CRs.
Page subscriptions. Get notified when watched pages change. One CR.
Public sharing. Generate read-only links to specific pages for external collaborators. One CR with security review.
AI summarization. Summarize long pages, extract action items from postmortems. One or two CRs with LLM integration.
Service catalog integration. Link runbooks to specific services in your service catalog. One CR with API integration.
Each is incremental. Ship the v1 core first.