Quick Start β’ Documentation β’ Examples β’ Contributing
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.
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 β¨
- β‘ 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
- π‘οΈ 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
- πΎ 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
# 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)
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.jsmkdir -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' },
});
};curl http://localhost:3000/hello
# Output: Hello from NanoWarp! πimport { NanoWarp } from 'nanowarp';
// Custom port and data directory
const server = new NanoWarp(8080, './my-data');
await server.start();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/login
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
};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)
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' }
});
}
};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/todosdata/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"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/healthBuilt-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,
};| 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 |
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
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 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 |
| 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 |
βββββββββββββββββββββββββββββββββββββββββββ
β 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)β β
β βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββ
We welcome contributions! Here's how you can help:
# 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 build- 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
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Bun and Node.js
- Inspired by modern file-based frameworks
- Community feedback and contributions
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Full Documentation
Made with β€οΈ by the NanoWarp team