nanowarp
v1.0.4
Published
Lightning-fast API framework with hot-swappable file-based endpoints (works with Bun and Node.js)
Maintainers
Readme
NanoWarp
Lightning-Fast API Framework with Hot-Swappable File-Based Endpoints
Quick Start • Documentation • Examples • Contributing
🚀 Overview
NanoWarp is a modern, high-performance API framework that eliminates the complexity of traditional backend development. Built with cross-runtime compatibility for both Bun and Node.js, it offers instant hot-reload, file-based routing, and production-grade reliability—all in a lightweight, dependency-minimal package.
Core Philosophy
Drop a .ts file in a folder → instant API endpoint. Edit it → changes apply immediately.
No restart. No rebuild. No configuration.
// data/Endpoints/GET/hello.ts
export const execute = async (path, request, Database) => {
return new Response('Hello World!');
};Access your endpoint: http://localhost:3000/hello ✨
✨ Key Features
Developer Experience
- ⚡ Hot Reload - File watcher detects changes and reloads endpoints instantly
- 📁 File-Based Routing - File location maps directly to API paths
- 🎯 Zero Configuration - No config files, no build steps, just code
- 📦 Minimal Dependencies - Lightweight footprint for fast installs and deploys
- 🔄 Cross-Runtime - Works seamlessly on both Bun and Node.js
Production Ready
- 🛡️ Error Boundaries - Endpoint crashes don't kill the server
- ⏱️ Request Timeouts - 30-second automatic timeout prevents infinite loops
- 🔐 API Key Authentication - Built-in auth with expiration and path whitelisting
- 📊 Rate Limiting - Token bucket algorithm prevents abuse
- 🔒 Atomic Operations - File-level locks prevent data corruption
- 🧹 Graceful Shutdown - Waits for in-flight requests before stopping
Data Management
- 💾 File-Based Database - Your filesystem IS the database
- ⚛️ Atomic Writes - Temp file + atomic rename ensures data integrity
- 🔐 Mutex Locks - Per-file write queues prevent concurrent write issues
- 📂 Directory Indexing - Fast lookups with cached directory structure
📦 Installation
# Using npm
npm install nanowarp
# Using Bun
bun add nanowarp
# Using pnpm
pnpm add nanowarp
# Using yarn
yarn add nanowarpRequirements:
- Node.js 18+ or Bun 1.0+
- TypeScript 5.0+ (recommended)
🚀 Quick Start
1. Create Your Server
import { NanoWarp } from 'nanowarp';
// Default configuration (port 3000, ./data directory)
const server = new NanoWarp();
await server.start();
console.log('🚀 Server running on http://localhost:3000');Run with Bun (recommended):
bun server.tsRun with Node.js:
npx tsx server.ts
# or after building: node dist/server.js2. Create Your First Endpoint
mkdir -p data/Endpoints/GETCreate data/Endpoints/GET/hello.ts:
export const execute = async (path: string, request: Request, Database: any) => {
return new Response('Hello from NanoWarp! 👋', {
status: 200,
headers: { 'Content-Type': 'text/plain' },
});
};3. Test Your Endpoint
curl http://localhost:3000/hello
# Output: Hello from NanoWarp! 👋Custom Configuration
import { NanoWarp } from 'nanowarp';
// Custom port and data directory
const server = new NanoWarp(8080, './my-data');
await server.start();📖 Documentation
File-Based Routing
File paths automatically map to URL endpoints based on HTTP method and location:
data/Endpoints/
├── GET/
│ ├── users.ts → GET /users
│ ├── users/
│ │ └── profile.ts → GET /users/profile
│ └── health.ts → GET /health
└── POST/
├── users.ts → POST /users
└── auth/
└── login.ts → POST /auth/loginEndpoint Structure
Every endpoint must export an execute function. Optionally, you can export rateLimit and schema configurations:
// Required: Execute function
export const execute = async (
path: string, // The request path (e.g., "users/profile")
request: Request, // Web Standards Request object
Database: DataManager // NanoWarp database manager instance
): Promise<Response> => {
// Your endpoint logic here
return new Response('Success', {
status: 200,
headers: { 'Content-Type': 'text/plain' }
});
};
// Optional: Rate limiting configuration (disabled by default)
export const rateLimit = {
enabled: true,
maxTokens: 100,
refillRate: 10,
refillInterval: 1000,
};
// Optional: OpenAPI schema (auto-generated defaults if not provided)
export const schema = {
summary: 'Endpoint description',
description: 'Detailed endpoint documentation',
tags: ['API'],
// ... other OpenAPI schema properties
};Working with Data
NanoWarp provides a simple yet powerful file-based data API:
// Read data
const data = await Database.retrieveData('./data/users.json');
// Write data (atomic + locked for safety)
await Database.saveData('./data/users.json', JSON.stringify(data));
// Delete data
await Database.deleteData('./data/users.json');Smart Data Handling:
.jsonand.lockfiles → Parsed JSON object- Directories → Array of filenames
- Other files → ArrayBuffer (binary data)
💡 Examples
Complete REST API: Todo Application
GET Endpoint - List Todos
data/Endpoints/GET/todos.ts:
// Only the execute function is required
export const execute = async (path, request, Database) => {
try {
const todos = await Database.retrieveData('./data/todos.json') || [];
return new Response(JSON.stringify(todos), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Failed to retrieve todos' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};POST Endpoint - Create Todo
data/Endpoints/POST/todos.ts:
export const execute = async (path, request, Database) => {
try {
const body = await request.json();
// Validate input
if (!body.title) {
return new Response(JSON.stringify({ error: 'Title is required' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// Retrieve existing todos
const todos = await Database.retrieveData('./data/todos.json') || [];
// Create new todo
const newTodo = {
id: Date.now(),
title: body.title,
completed: false,
createdAt: new Date().toISOString()
};
todos.push(newTodo);
// Save atomically
await Database.saveData('./data/todos.json', JSON.stringify(todos, null, 2));
return new Response(JSON.stringify(newTodo), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Failed to create todo' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};Test Your API:
# Create a todo
curl -X POST http://localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"title":"Build awesome API"}'
# List all todos
curl http://localhost:3000/todosQuery Parameters and URL Parsing
data/Endpoints/GET/users/search.ts:
export const execute = async (path, request, Database) => {
const url = new URL(request.url);
const name = url.searchParams.get('name');
const limit = parseInt(url.searchParams.get('limit') || '10');
// Fetch and filter users
const allUsers = await Database.retrieveData('./data/users.json') || [];
const filtered = name
? allUsers.filter(u => u.name.includes(name))
: allUsers;
return new Response(JSON.stringify(filtered.slice(0, limit)), {
headers: { 'Content-Type': 'application/json' }
});
};# Test with query parameters
curl "http://localhost:3000/users/search?name=John&limit=5"🔐 Security
API Key Authentication
Create data/apikeys.json:
{
"keys": {
"prod-key-abc123": "2025-12-31T23:59:59.000Z",
"dev-key-xyz789": "2024-06-30T23:59:59.000Z"
},
"whitelist": ["/health", "/public"]
}Features:
- ⏱️ Automatic Expiration - Keys expire based on ISO date
- 🎯 Path Whitelisting - Public endpoints bypass authentication
- 💾 60-Second Cache - Reduces file I/O overhead
- 🔓 Optional Auth - No keys file = no authentication required
Usage:
# Authenticated request
curl -H "X-API-Key: prod-key-abc123" http://localhost:3000/users
# Whitelisted path (no key required)
curl http://localhost:3000/healthRate Limiting
Built-in token bucket algorithm protects against abuse:
- Disabled by default - Enable per endpoint as needed
- Per-endpoint configuration - Different limits for different endpoints
- 100 tokens per IP (configurable)
- Refills at 10 tokens/second (configurable)
- Automatic cleanup of inactive IPs
- 429 Too Many Requests response when limit exceeded
Enable rate limiting by exporting a rateLimit configuration in your endpoint:
export const rateLimit = {
enabled: true,
maxTokens: 100,
refillRate: 10,
refillInterval: 1000,
};⚡ Performance & Reliability
Production Features
| Feature | Description | |---------|-------------| | Error Boundaries | Endpoint crashes are isolated—server stays healthy | | 30s Timeout | Automatic termination of long-running requests | | Atomic Writes | Temp file + atomic rename prevents data corruption | | File Locks | Mutex-based locking prevents concurrent write issues | | Graceful Shutdown | Waits for in-flight requests before stopping | | Hot Reload | File watcher detects changes, reloads instantly | | LRU Cache | Smart module caching with auto-eviction (100 entry limit) | | Cross-Runtime | Zero-overhead abstraction for Bun and Node.js |
How It Works
graph LR
A[Request] --> B[Server]
B --> C{Auth Check}
C -->|Valid| D[Route to Endpoint]
C -->|Invalid| E[401 Unauthorized]
D --> F{Module Cached?}
F -->|Yes| G[Execute]
F -->|No| H[Import & Cache]
H --> G
G --> I[Response]Technical Implementation:
- Module Caching - Endpoints cached until file changes detected
- File Watching -
fs.watch()monitors endpoint files for changes - Version Busting -
import(path?v=N)forces fresh imports after edits - Atomic Writes - Write to
.tmp→fs.rename()(POSIX guarantees atomicity) - Mutex Locks - Per-file write queue prevents race conditions
- LRU Eviction - Least-recently-used modules evicted when cache reaches 100 entries
📁 Project Structure
your-project/
├── data/ # Data directory (customizable)
│ ├── apikeys.json # Optional: API authentication config
│ ├── database.lock # Auto-generated: directory structure cache
│ ├── Endpoints/ # Your API endpoints
│ │ ├── GET/
│ │ │ ├── users.ts # GET /users
│ │ │ ├── users/
│ │ │ │ └── profile.ts # GET /users/profile
│ │ │ └── health.ts # GET /health
│ │ └── POST/
│ │ ├── users.ts # POST /users
│ │ └── auth/
│ │ └── login.ts # POST /auth/login
│ ├── users.json # Your data (any structure)
│ └── todos.json # More data
├── server.ts # Your server entry point
└── package.json🎯 Use Cases
✅ Perfect For
| Use Case | Why NanoWarp Excels | |----------|---------------------| | Rapid Prototyping | Zero configuration, instant endpoints | | Microservices | Fast startup, minimal footprint (~5MB) | | Webhooks | Hot-swap logic without downtime | | Edge Computing | Minimal dependencies, cross-runtime | | Version Control | Endpoints are files—easy git workflows | | Internal Tools | Simple APIs for dashboards and automation | | Learning Projects | No database complexity, focus on logic |
⚠️ Not Recommended For
| Scenario | Better Alternative | |----------|-------------------| | High-concurrency writes to same file | PostgreSQL, MySQL, MongoDB | | Complex relational queries | SQLite, PostgreSQL | | Multi-TB datasets | Traditional DBMS with indexing | | Netflix-scale traffic | Distributed DB + CDN + caching layer |
🏗️ Architecture
Core Components
┌─────────────────────────────────────────┐
│ NanoWarp Server │
├─────────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Server │────│ Rate Limiter │ │
│ │ (HTTP) │ │ (Token Bucket)│ │
│ └──────┬──────┘ └──────────────┘ │
│ │ │
│ ┌──────▼──────┐ ┌──────────────┐ │
│ │ Auth Layer │────│ API Keys │ │
│ │ (Optional) │ │ Cache │ │
│ └──────┬──────┘ └──────────────┘ │
│ │ │
│ ┌──────▼──────┐ ┌──────────────┐ │
│ │ Router │────│Module Cache │ │
│ │ (File-Based)│ │ (LRU) │ │
│ └──────┬──────┘ └──────────────┘ │
│ │ │
│ ┌──────▼──────┐ ┌──────────────┐ │
│ │ Endpoint │────│File Watcher │ │
│ │ Executor │ │(Hot Reload) │ │
│ └──────┬──────┘ └──────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Database │ │
│ │ Manager │ │
│ │ (File-Based)│ │
│ └─────────────┘ │
└─────────────────────────────────────────┘🤝 Contributing
We welcome contributions! Here's how you can help:
Development Setup
# Clone the repository
git clone https://github.com/ncwardell/NanoWarp.git
cd NanoWarp
# Install dependencies
bun install
# Run tests
bun test
# Build the project
bun run buildContributing Guidelines
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please ensure:
- ✅ Code follows existing style conventions
- ✅ All tests pass
- ✅ New features include tests
- ✅ Documentation is updated
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with Bun and Node.js
- Inspired by modern file-based frameworks
- Community feedback and contributions
📞 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Full Documentation
Made with ❤️ by the NanoWarp team
