A powerful AI-driven story writing web application built with Express, React, and TypeScript.
The Story Nexus is a local-first web application designed for writers who want to leverage AI to enhance their creative writing process. It provides a comprehensive environment for creating, organizing, and developing stories with the assistance of AI-powered tools. Run it on your local machine or deploy it via Docker to access from any device on your network.
Based on work started by Vijaykumar Bhattacharji; now extensively rewritten, reworked and reimagined.
I wasn't happy with the IndexedDB-based database because I couldn't share data between devices, and I wanted a more robust backend architecture. So I rewrote the backend using Express.js and SQLite with Drizzle ORM.
I didn't like Tauri because I wanted a web app that could run on any device without installing a desktop app, and possibly from a Docker container on my home server. So it was goodbye Tauri.
The code quality has been improved significantly too, and I'm gradually ripping out custom code in favor of established libraries and patterns.
I'm also in the process of reworking the UI/UX to be more of a writer's workspace.
- Story Management: Create and organize your stories with chapters, outlines, and summaries
- Rich Text Editor: Write and edit your stories using a powerful Lexical-based editor
- AI Integration: Generate content using AI models from OpenAI, Google Gemini, OpenRouter, or locally hosted models
- Custom Prompts: Create and manage custom prompts to guide AI generation
- Scene Beats Addon to Editor: Press alt (option for mac) + s in editor to open Scene Beat AI command
- Lorebook: Maintain a database of characters, locations, items, events, and notes for your story
- Local-First: All your data is stored locally in a SQLite database
- Data Migration: Import data from previous IndexedDB-based versions or export your current database
- Backend: Express.js, SQLite, Drizzle ORM, better-sqlite3
- Frontend: React, TypeScript, Vite, Tailwind CSS, Shadcn UI
- State Management: TanStack Query v5
- Routing: React Router v7
- Database: SQLite with Drizzle ORM
- Text Editor: Lexical v0.24.0
- UI Components: Shadcn UI, Lucide React icons
- Notifications: React Toastify
- Development: tsx watch (backend), Vite HMR (frontend), concurrently
- Node.js 20+
- npm or yarn
-
Clone the repository
-
Install dependencies:
npm install
-
Start both backend and frontend servers:
npm run dev
This runs both:
- Backend API server on
http://localhost:3001 - Frontend dev server on
http://localhost:5173(with proxy to backend)
- Backend API server on
-
Open
http://localhost:5173in your browser
npm run dev:server # Backend only (Express + SQLite)
npm run dev:client # Frontend only (Vite)-
Build both backend and frontend:
npm run build
-
Start production server:
npm start
App runs on
http://localhost:3000(configurable viaPORTenvironment variable)
npm run db:generate # Generate migration from schema changes
npm run db:migrate # Apply migrations to databasePull and run the latest published image from Docker Hub:
docker-compose up -dSupports linux/amd64, linux/arm64, and linux/arm/v7 architectures.
Access on http://localhost:3000 or from any device on your network using your machine's IP address.
Database persists in ./data/storynexus.db (mounted volume).
Version pinning:
# docker-compose.yml
services:
storynexus:
image: jonsilver/storynexus:0.6.0 # Pin to specific version
# or: jonsilver/storynexus:0.6 # Auto-update patches
# or: jonsilver/storynexus:latest # Latest releaseBuild and run from source:
docker-compose -f docker-compose.dev.yml up --buildNew releases are published via GitHub Releases, which automatically builds and pushes multi-architecture Docker images to Docker Hub.
Creating a release:
Using the PowerShell script (Windows):
.\release.ps1 patch # 0.6.0 → 0.6.1
.\release.ps1 minor # 0.6.0 → 0.7.0
.\release.ps1 major # 0.6.0 → 1.0.0The script automatically bumps the version, pushes to GitHub, and opens the release page in your browser.
Manual process:
- Bump version:
npm version <patch|minor|major> - Push:
git push && git push --tags - Create GitHub release from the tag (via GitHub UI)
Result - Workflow automatically builds and pushes Docker images with tags:
jonsilver/storynexus:0.7.0(specific version)jonsilver/storynexus:0.7(minor version)jonsilver/storynexus:0(major version)jonsilver/storynexus:latestjonsilver/storynexus:sha-abc1234(commit hash)
Note: Docker images are only built on releases, not on every commit to main.
server/- Express.js API serverdb/- Database schema, client, migrations, and seedingroutes/- API route handlers (stories, chapters, prompts, lorebook, etc.)index.ts- Server entry point
src/features/- Feature modules (stories, chapters, prompts, ai, lorebook, brainstorm, notes)*/hooks/- TanStack Query hooks for data fetching*/pages/- Route components*/components/- Feature-specific UI components
src/components/- Reusable UI componentssrc/Lexical/- Text editor implementation (custom Lexical editor)src/services/- Services (AI, database, export utilities, API client)src/types/- TypeScript type definitionssrc/lib/- Utility functions and helpers
Export and import your entire database from the AI Settings page:
Export: Downloads a JSON file containing all your data (stories, chapters, prompts, lorebook entries, etc.)
Import: Replaces all current data with data from a JSON file. System prompts are preserved.
Migration workflow:
- Export from old IndexedDB-based version (if migrating)
- Import into new SQLite-based version
- System prompts automatically initialized on first run
Export and import individual prompts from the Prompts Manager UI:
Export: Downloads non-system prompts only (system prompts excluded)
Import: Validates and creates imported prompts as non-system (editable). Duplicate names get (Imported) suffix. New IDs and timestamps generated.
Format:
{
"version": "1.0",
"type": "prompts",
"prompts": [
/* array of prompt objects */
]
}- Replace the component-based guide with markdown-driven documentation presented by a small set of components.







